Uma lista que se redimensiona sozinha
Um array comum do Java tem um comprimento fixo: se você decidir por dez espaços, terá dez espaços para sempre. ArrayList é a alternativa redimensionável do java.util - ele cresce conforme você adiciona e encolhe conforme você remove, e traz métodos úteis para o que você realmente faz com uma lista.
Repare no tipo entre os sinais de menor e maior - List<String> - que diz ao compilador que esta lista armazena valores String. O <> (o "diamante") à direita permite que o Java infira o mesmo tipo sem repeti-lo. E observe que você importa java.util.ArrayList; ele não está disponível por padrão.
Declare como List, construa como ArrayList
Você quase sempre verá a variável declarada com a interface List em vez do ArrayList concreto:
List<String> names = new ArrayList<>();
É um bom hábito, não uma regra. Programar para a interface List significa que o resto do seu código não se importa com qual implementação de lista você usou, então você pode trocá-la por outra mais tarde sem mexer nele. Para o uso do dia a dia, as duas se comportam da mesma forma.
Adicionar, obter e alterar
add(value)adiciona no final.add(index, value)insere numa posição, deslocando os elementos posteriores para a direita.get(index)lê o elemento numa posição (começando em zero).set(index, value)sobrescreve um elemento existente.
Os índices começam em zero, e get em um índice fora do intervalo lança IndexOutOfBoundsException.
Removendo elementos
Existe uma armadilha clássica quando a lista armazena Integer. remove(int) é "remover pelo índice" e remove(Object) é "remover pelo valor", então:
List<Integer> nums = new ArrayList<>(List.of(10, 20, 30));
nums.remove(1); // remove o índice 1 -> o valor 20
nums.remove(Integer.valueOf(20)); // remove o valor 20
Envolva o valor em Integer.valueOf(...) quando você quer dizer "remova este valor", e não "remova este índice".
Tamanho, contains e buscas por índice
List.of(...) cria rapidamente uma lista imutável; passá-la ao construtor do ArrayList te dá uma cópia mutável já preenchida com esses valores.
Percorrendo um ArrayList
O laço mais limpo é o for aprimorado (o "for-each"):
Quando você também precisa do índice, use um laço contado com size() e get(i):
Uma regra: não adicione nem remova elementos de uma lista enquanto um laço for-each a percorre - isso lança ConcurrentModificationException. Para apagar itens correspondentes com segurança, use removeIf:
Ordenação
Collections.sort ordena uma lista no próprio local usando a ordem natural (alfabética para strings, numérica para números):
Para ordenações personalizadas, passe um Comparator para list.sort(...) - por exemplo names.sort(Comparator.comparingInt(String::length)) para ordenar pelo comprimento.
ArrayList armazena objetos, não primitivos
Você não pode escrever ArrayList<int>. Os genéricos só funcionam com tipos de objeto, então use a classe wrapper Integer, Double, Boolean e assim por diante:
O autoboxing do Java converte para você entre int e Integer, então isto se lê de forma natural - só lembre que a própria lista armazena objetos Integer.
Próximo: HashMap
ArrayList é a ferramenta certa quando você se importa com a ordem e a posição. Quando você precisa buscar coisas por uma chave - um nome de usuário para um usuário, um código de produto para um preço - você quer um HashMap, que é a próxima página.
Perguntas frequentes
Como criar um ArrayList em Java?
Declare-o com o tipo dos elementos entre os sinais de menor e maior e chame o construtor: ArrayList<String> names = new ArrayList<>();. O <> à direita (o diamante) permite que o Java infira o tipo. Normalmente você declara a variável com a interface List: List<String> names = new ArrayList<>();.
Qual é a diferença entre um array e um ArrayList em Java?
Um array comum tem um comprimento fixo definido no momento da criação e pode armazenar primitivos como int. Um ArrayList cresce e encolhe automaticamente conforme você adiciona e remove elementos, armazena apenas objetos (então int vira Integer) e vem com métodos como add, remove, contains e size. Use um array para dados primitivos de tamanho fixo; use um ArrayList quando o tamanho muda.
Como remover um elemento de um ArrayList?
Chame remove(index) para remover pela posição, ou remove(object) para remover o primeiro elemento que corresponder. Cuidado com listas de Integer: list.remove(2) remove o índice 2, enquanto list.remove(Integer.valueOf(2)) remove o valor 2. Para remover enquanto percorre a lista, use o remove() de um Iterator ou removeIf(...) para evitar uma ConcurrentModificationException.