Interface List em Java
Coleções ordenadas e acessíveis por índice em Java com a interface List e suas operações principais.
List<E> é Collection<E> com dois compromissos extras: os elementos têm uma ordem definida, e essa ordem é endereçável por índice inteiro. Uma vez que você tem ordem e índice, toda uma classe de métodos faz sentido — get(i), set(i, x), indexOf(x), subList(from, to), ordenação, iteração em ordem inversa. Este capítulo percorre o contrato; as implementações (ArrayList, LinkedList, Vector) aparecem logo em seguida com suas próprias características de desempenho.
O que "ordenado" significa aqui
"Ordenado" em uma List significa que a ordem de inserção é preservada — índice 0 é o primeiro elemento que você inseriu, índice size() - 1 é o último, e adicionar um novo elemento ao final não desloca nada. Isso não significa "ordenado" — uma lista mantém qualquer ordem que você produza. Se quiser iteração ordenada, você pode chamar Collections.sort(list) (que muta a lista) ou usar TreeSet / TreeMap desde o início. Não confunda os dois.
Duplicatas são permitidas. [1, 1, 2, 1] é uma List<Integer> completamente válida.
Os métodos que List adiciona sobre Collection
Tudo que Collection declara ainda está lá — add, remove, contains, size, etc. List então adiciona operações posicionais e sensíveis à ordem:
Acesso posicional
E get(int index)— elemento noindex.E set(int index, E element)— substitui, retornando o valor antigo.void add(int index, E element)— insere (desloca elementos posteriores para a direita).E remove(int index)— remove pela posição (retorna o elemento removido). Observe a sobrecarga comObject—list.remove(1)chama a versãoint;list.remove(Integer.valueOf(1))chama a versãoObject.
Busca
int indexOf(Object o)— primeira ocorrência, ou-1.int lastIndexOf(Object o)— última ocorrência, ou-1.
Sub-visões e iteração
List<E> subList(int fromIndex, int toIndex)— uma visão ativa de um intervalo. Modificá-la modifica a lista de suporte (e vice-versa). Intervalo semiaberto:[from, to).ListIterator<E> listIterator()/listIterator(int index)— iterador que também pode percorrer em sentido inverso, obter o índice atual eset/addna posição do cursor. O capítulo ListIterator cobre isso.
Mutação em lote vinculada à ordem
default void replaceAll(UnaryOperator<E> op)— aplicaopa cada elemento no lugar.default void sort(Comparator<? super E> c)— ordena a lista usandoc(ou ordem natural senull).boolean addAll(int index, Collection<? extends E> c)— insere uma coleção inteira noindex.
Fábricas (Java 9+)
List.of(...)— uma lista não modificável com os elementos fornecidos. Compacta, sem alocação para tamanhos pequenos.List.copyOf(Collection)— um snapshot não modificável de outra coleção.
Igualdade em List é sensível à ordem
Duas listas são iguais se e somente se têm o mesmo tamanho, na mesma ordem, com elementos iguais em cada índice. List.of(1, 2) não é igual a List.of(2, 1), mesmo que como Sets fossem. Essa é uma regra rígida do contrato de List — se você está comparando duas listas e obtendo false quando "não deveria," verifique a ordem primeiro.
subList é uma visão, não uma cópia
Isso engana quase todo iniciante ao menos uma vez:
List<Integer> xs = new ArrayList<>(List.of(0, 1, 2, 3, 4, 5));
List<Integer> middle = xs.subList(2, 5); // [2, 3, 4]
middle.set(0, 99);
System.out.println(xs); // [0, 1, 99, 3, 4, 5] — xs changed!
middle.clear();
System.out.println(xs); // [0, 1, 5] — gone from xssubList retorna uma janela ativa. Leituras e escritas passam pela lista de suporte. Isso é extremamente útil para algoritmos no lugar — limpar um intervalo, ordenar um intervalo, inserir um intervalo — mas também significa que você não pode manter uma referência de subList e depois mutar o pai por outro caminho. O Javadoc diz que alterações estruturais na lista de suporte fora da sub-lista "indefinem" o comportamento da sub-lista. Na prática, ConcurrentModificationException na próxima chamada.
Se quiser uma fatia independente, copie-a: new ArrayList<>(xs.subList(2, 5)).
As duas sobrecargas de remove
Um bug comum:
List<Integer> nums = new ArrayList<>(List.of(10, 20, 30));
nums.remove(1); // removes index 1 → [10, 30]
nums.remove(Integer.valueOf(10)); // removes the value 10 → [30]A sobrecarga int vence porque int é mais específico que Integer. Se você quer "remover o valor 10," encapsule-o explicitamente. Este é um dos poucos lugares na linguagem onde as regras de autoboxing e resolução de sobrecarga entram em conflito ativo.
Ordenação no lugar
list.sort(comparator) muta a lista. Passe null para usar a ordem natural dos elementos (seu Comparable); passe um Comparator caso contrário. Esta é a forma moderna — Collections.sort(list) ainda funciona e é idêntico, mas list.sort(...) é o método padrão de List:
List<String> names = new ArrayList<>(List.of("Linus", "Ada", "Grace"));
names.sort(null); // natural: ["Ada", "Grace", "Linus"]
names.sort(Comparator.comparingInt(String::length)); // shortest firstO capítulo Comparable / Comparator mais adiante nesta parte é o manual sobre o que null significa e como construir comparadores para seus próprios tipos.
Fábricas imutáveis: quando add lança exceção
List.of(...), List.copyOf(...) e as listas retornadas por Collectors.toUnmodifiableList() são não modificáveis. Elas rejeitam toda chamada de mutação com UnsupportedOperationException. Elas também rejeitam elementos null. São ideais para dados somente leitura compartilhados amplamente:
List<String> CONSTANTS = List.of("red", "green", "blue");
CONSTANTS.add("yellow"); // throws UnsupportedOperationExceptionSe você quiser mutar depois, comece com new ArrayList<>(List.of(...)).
Um exemplo prático: todos os métodos específicos de List
O programa abaixo exercita os métodos que List adiciona além de Collection. Observe a propagação da mutação de subList, a armadilha da sobrecarga e a diferença entre sort e replaceAll.
Algumas conclusões da saída que você deve guardar:
remove(1)removeu20(o valor no índice 1);remove(Integer.valueOf(10))removeu10pelo valor. Mesmo nome de método, dois trabalhos diferentes com base no tipo estático do argumento.- Após
mid.clear(), a lista pai é[0, 1, 5]. A visão era o intervalo — limpá-la removeu esses elementos do array de suporte. replaceAllmantém a lista com o mesmo tamanho e reescreve cada elemento no lugar;sortreorganiza o que já está lá. Eles se compõem bem.
O que vem a seguir
Você agora conhece o contrato de List — o que é garantido, o que muta o quê, onde estão as armadilhas. É hora de conhecer a implementação que você usará 90% do tempo: a ArrayList com suporte em array redimensionável. Mesmo contrato, características de desempenho específicas e alguns extras próprios.