W3docs

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 no index.
  • 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 com Objectlist.remove(1) chama a versão int; list.remove(Integer.valueOf(1)) chama a versão Object.

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 e set / add na posição do cursor. O capítulo ListIterator cobre isso.

Mutação em lote vinculada à ordem

  • default void replaceAll(UnaryOperator<E> op) — aplica op a cada elemento no lugar.
  • default void sort(Comparator<? super E> c) — ordena a lista usando c (ou ordem natural se null).
  • boolean addAll(int index, Collection<? extends E> c) — insere uma coleção inteira no index.

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 xs

subList 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 first

O 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 UnsupportedOperationException

Se 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.

java— editable, runs on the server

Algumas conclusões da saída que você deve guardar:

  • remove(1) removeu 20 (o valor no índice 1); remove(Integer.valueOf(10)) removeu 10 pelo 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.
  • replaceAll mantém a lista com o mesmo tamanho e reescreve cada elemento no lugar; sort reorganiza 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.

Prática

Prática
`xs` é `new ArrayList<>(List.of(10, 20, 30, 40))`. Você chama `xs.subList(1, 3).clear()`. Qual é o valor de `xs` depois?
`xs` é `new ArrayList<>(List.of(10, 20, 30, 40))`. Você chama `xs.subList(1, 3).clear()`. Qual é o valor de `xs` depois?
Was this page helpful?