Java ArrayList
A ArrayList é a coleção mais usada do Java: uma lista de elementos em ordem, cada um numa posição numerada, que cresce e encolhe conforme você acrescenta e remove. Pense nela como um array "elástico". Nesta aula você vai aprender cada operação, uma de cada vez, com as saídas reais e os erros mais comuns.
- Criar uma
ArrayListe acrescentar elementos comadd(no fim ou numa posição). - Ler com
get, trocar comsete saber o tamanho comsize. - Remover por posição e por valor, e a pegadinha do
removecomInteger. - Procurar com
containseindexOf. - Percorrer a lista de três jeitos e ordená-la.
- O que são
IndexOutOfBoundsExceptioneUnsupportedOperationException(comList.of).
Se você caiu aqui direto, leia antes a Visão Geral das Coleções: ela explica por que existem coleções e o que quer dizer List<String> x = new ArrayList<>(). Todas as saídas abaixo vieram do JDK 25, na máquina da Ana.
A ideia: uma lista de compras
Na geladeira da Ana há uma lista de compras. Ela escreve um item embaixo do outro, às vezes encaixa um no meio, risca os que comprou e troca "feijão" por "feijão preto". Cada linha tem uma posição: o primeiro item, o segundo… A ArrayList é exatamente isso, com uma diferença: as posições começam em 0, como nos arrays.
posição: 0 1 2 3
[arroz] [leite] [feijão] [café]
Por dentro, a ArrayList guarda os elementos num array comum. Quando ele enche, ela cria outro array maior, copia tudo e continua; você nunca vê isso acontecer. Daí o nome: Array (guarda num array) + List (é uma lista).
Criar e acrescentar: add
import java.util.ArrayList;
import java.util.List;
public class Main {
public static void main(String[] args) {
List<String> compras = new ArrayList<>();
System.out.println("Vazia: " + compras + " tamanho " + compras.size());
compras.add("arroz");
compras.add("feijão");
compras.add("café");
System.out.println("Depois de 3 add: " + compras);
compras.add(1, "leite");
System.out.println("add(1, \"leite\"): " + compras);
}
}
- import java.util.ArrayList; import java.util.List;
- Traz a classe
ArrayListe a interfaceListdo pacotejava.util. - List<String> compras
- Uma variável chamada
compras, do tipo "lista deString". Só textos entram nela. - new ArrayList<>()
- Cria a lista vazia. O
<>("diamante") repete o tipo do lado esquerdo. - compras.add("arroz")
add(acrescentar) com um argumento põe o elemento no fim.- compras.add(1, "leite")
- Com dois argumentos, o primeiro é a posição: "encaixe
leitena posição 1". Quem estava ali e depois anda uma casa para a direita.
$ javac Main.java $ java Main Vazia: [] tamanho 0 Depois de 3 add: [arroz, feijão, café] add(1, "leite"): [arroz, leite, feijão, café] « feijão e café andaram uma posição
Uma lista vazia aparece como []. Depois do add(1, "leite"), o feijão (que estava na posição 1) foi para a 2, e o café foi da 2 para a 3. A posição pode ir de 0 até size(): add(size(), x) é o mesmo que add(x).
Ler, trocar e contar: get, set, size
Continuando o mesmo programa:
String primeiro = compras.get(0);
System.out.println("get(0): " + primeiro);
System.out.println("get(3): " + compras.get(3));
String antigo = compras.set(2, "feijão preto");
System.out.println("set(2, ...) trocou " + antigo + ": " + compras);
System.out.println("Tamanho: " + compras.size());
| Método | Tradução | O que faz | Devolve |
|---|---|---|---|
get(i) | pegar | Lê o elemento da posição i, sem tirá-lo da lista. É o lista[i] dos arrays. | O elemento |
set(i, x) | definir | Troca o elemento da posição i por x. O tamanho não muda. | O elemento antigo |
size() | tamanho | Quantos elementos há agora. | Um int |
$ javac Main.java $ java Main Vazia: [] tamanho 0 Depois de 3 add: [arroz, feijão, café] add(1, "leite"): [arroz, leite, feijão, café] get(0): arroz get(3): café set(2, ...) trocou feijão: [arroz, leite, feijão preto, café] « set devolveu o valor que saiu Tamanho: 4
add(i, x) encaixa; set(i, x) substitui
Com add(1, "leite") a lista ganhou um elemento (de 3 para 4). Com set(2, "feijão preto") ela continuou com 4: o feijão saiu e o feijão preto entrou no lugar. Trocar um pelo outro é um erro comum.
Como as posições começam em 0, o último está em size() - 1: compras.get(compras.size() - 1). No Java 21 em diante também existe compras.getLast() (e getFirst()) Java 21+.
Remover: por posição ou por valor
O remove tem duas versões, e é aqui que mora a maior pegadinha da ArrayList:
| Chamada | Remove… | Devolve |
|---|---|---|
remove(int posicao) | o elemento daquela posição | o elemento removido |
remove(Object valor) | a primeira ocorrência daquele valor | true se achou e removeu, false se não achou |
import java.util.ArrayList;
import java.util.List;
public class Main {
public static void main(String[] args) {
List<String> alunos = new ArrayList<>();
alunos.add("Ana");
alunos.add("Bruno");
alunos.add("Carla");
alunos.add("Bruno");
System.out.println("Início: " + alunos);
String saiu = alunos.remove(0);
System.out.println("remove(0) tirou " + saiu + ": " + alunos);
boolean achou = alunos.remove("Bruno");
System.out.println("remove(\"Bruno\") -> " + achou + ": " + alunos);
boolean achou2 = alunos.remove("Zeca");
System.out.println("remove(\"Zeca\") -> " + achou2 + ": " + alunos);
}
}
$ javac Main.java
$ java Main
Início: [Ana, Bruno, Carla, Bruno]
remove(0) tirou Ana: [Bruno, Carla, Bruno] « por posição: devolveu quem saiu
remove("Bruno") -> true: [Carla, Bruno] « por valor: só o PRIMEIRO Bruno
remove("Zeca") -> false: [Carla, Bruno] « não achou: false, e nada muda
Repare em três coisas: depois de remove(0) todos andaram uma casa para a esquerda (o Bruno virou o 0); remove("Bruno") tirou só o primeiro Bruno; e remover algo que não existe não é erro, só devolve false.
A pegadinha: remove numa lista de Integer
Numa lista de textos, remove(0) e remove("Bruno") não se confundem: um é número, o outro é texto. Mas e numa lista de números? A Ana guarda as notas de uma prova e quer tirar a nota 3, que foi lançada por engano:
import java.util.ArrayList;
import java.util.List;
public class Main {
public static void main(String[] args) {
List<Integer> notas = new ArrayList<>();
notas.add(10);
notas.add(7);
notas.add(3);
notas.add(5);
System.out.println("Notas: " + notas);
notas.remove(3); // a Ana quer tirar a nota 3...
System.out.println("Depois de remove(3): " + notas);
}
}
$ javac Main.java $ java Main Notas: [10, 7, 3, 5] Depois de remove(3): [10, 7, 3] « saiu o 5! O 3 continua lá
Nenhum erro, nenhum aviso, e o resultado está errado. O que aconteceu: 3, escrito assim, é um int. Entre as duas versões do remove, o Java escolhe a que encaixa sem conversão: remove(int posicao). Então ele removeu o elemento da posição 3, que é o 5.
Para dizer "remova o valor 3", o argumento precisa ser um objeto Integer, não um int. Há duas formas:
notas.remove(Integer.valueOf(3)); // forma 1: cria um Integer
notas.remove((Integer) 7); // forma 2: conversão (cast) para Integer
notas.remove(10); // isto é a POSIÇÃO 10...
$ javac Main.java $ java Main remove(Integer.valueOf(3)): [10, 7, 5] remove((Integer) 7): [10, 5] Exception in thread "main" java.lang.IndexOutOfBoundsException: Index 10 out of bounds for length 2 at java.base/jdk.internal.util.Preconditions.outOfBounds(Preconditions.java:100) at java.base/jdk.internal.util.Preconditions.outOfBoundsCheckIndex(Preconditions.java:106) at java.base/jdk.internal.util.Preconditions.checkIndex(Preconditions.java:302) at java.base/java.util.Objects.checkIndex(Objects.java:365) at java.base/java.util.ArrayList.remove(ArrayList.java:552) at Main.main(Main.java:18)
As duas primeiras formas removeram o valor certo. A terceira mostra o outro lado da pegadinha: a Ana queria tirar a nota 10, mas remove(10) pediu a posição 10 de uma lista com 2 elementos, e o programa parou com IndexOutOfBoundsException (as linhas at java.base/… são o caminho dentro da biblioteca do Java; a que importa é a última, Main.java:18, a sua linha).
Em List<Integer>, remove(numero) é sempre por posição. Para remover por valor, use remove(Integer.valueOf(numero)). Mais sobre int × Integer em Wrappers e Autoboxing.
Missão: rode e veja que a nota errada sai. Corrija a linha do remove para que saia a nota 3 (o valor) e a saída termine com Depois: [10, 7, 5].
import java.util.ArrayList;
import java.util.List;
public class Main {
public static void main(String[] args) {
List<Integer> notas = new ArrayList<>();
notas.add(10);
notas.add(7);
notas.add(3);
notas.add(5);
System.out.println("Notas: " + notas);
notas.remove(3);
System.out.println("Depois: " + notas);
}
}
import java.util.ArrayList;
import java.util.List;
public class Main {
public static void main(String[] args) {
List<Integer> notas = new ArrayList<>();
notas.add(10);
notas.add(7);
notas.add(3);
notas.add(5);
System.out.println("Notas: " + notas);
notas.remove(Integer.valueOf(3));
System.out.println("Depois: " + notas);
}
}
Procurar: contains, indexOf, isEmpty
import java.util.ArrayList;
import java.util.List;
public class Main {
public static void main(String[] args) {
List<String> frutas = new ArrayList<>();
frutas.add("maçã");
frutas.add("banana");
frutas.add("uva");
frutas.add("banana");
System.out.println("contains(\"uva\"): " + frutas.contains("uva"));
System.out.println("contains(\"kiwi\"): " + frutas.contains("kiwi"));
System.out.println("contains(\"Uva\"): " + frutas.contains("Uva"));
System.out.println("indexOf(\"banana\"): " + frutas.indexOf("banana"));
System.out.println("lastIndexOf(\"banana\"): " + frutas.lastIndexOf("banana"));
System.out.println("indexOf(\"kiwi\"): " + frutas.indexOf("kiwi"));
System.out.println("isEmpty(): " + frutas.isEmpty());
frutas.clear();
System.out.println("depois de clear(): " + frutas + " isEmpty(): " + frutas.isEmpty());
}
}
$ javac Main.java
$ java Main
contains("uva"): true
contains("kiwi"): false
contains("Uva"): false « maiúscula conta: "Uva" não é "uva"
indexOf("banana"): 1 « a posição da PRIMEIRA banana
lastIndexOf("banana"): 3 « a posição da ÚLTIMA
indexOf("kiwi"): -1 « -1 = "não está na lista"
isEmpty(): false
depois de clear(): [] isEmpty(): true
| Método | Pergunta | Resposta |
|---|---|---|
contains(x) | "x está na lista?" | true/false |
indexOf(x) | "Em que posição está o primeiro x?" | A posição, ou -1 |
lastIndexOf(x) | "E o último?" | A posição, ou -1 |
isEmpty() | "Está vazia?" (o mesmo que size() == 0) | true/false |
clear() | Apaga tudo. | nada (void) |
Para comparar, esses métodos usam o equals de cada elemento, o mesmo que você usa para comparar Strings ("uva".equals("Uva") é false). Com objetos criados por você, como uma classe Aluno, contains só funciona direito se a classe tiver equals; veja A Classe Object.
Percorrer a lista
Há três jeitos comuns de passar por todos os elementos:
import java.util.ArrayList;
import java.util.List;
public class Main {
public static void main(String[] args) {
List<String> alunos = new ArrayList<>();
alunos.add("Ana");
alunos.add("Bruno");
alunos.add("Carla");
// 1. for com índice
for (int i = 0; i < alunos.size(); i++) {
System.out.println((i + 1) + "º " + alunos.get(i));
}
// 2. for-each
for (String aluno : alunos) {
System.out.println("Olá, " + aluno + "!");
}
// 3. forEach com lambda
alunos.forEach(aluno -> System.out.println("Tchau, " + aluno));
}
}
$ javac Main.java $ java Main 1º Ana 2º Bruno 3º Carla Olá, Ana! Olá, Bruno! Olá, Carla! Tchau, Ana Tchau, Bruno Tchau, Carla
| Forma | Quando usar |
|---|---|
for (int i = 0; i < lista.size(); i++) | Quando você precisa da posição (numerar, comparar com o vizinho, mexer só nos pares…). Repare: size(), não length. |
for (String aluno : lista) | O mais comum: "para cada aluno da lista". Mais curto e sem risco de errar o índice. Veja for-each. |
lista.forEach(aluno -> …) | Uma linha só, no estilo funcional. A setinha -> é uma lambda, assunto do próximo grupo de aulas. |
Tirar elementos da lista enquanto um for-each passa por ela termina em ConcurrentModificationException. A aula Iterator mostra o erro real e as soluções (Iterator.remove e removeIf).
Ordenar
Há duas formas equivalentes de pôr a lista em ordem: o método estático Collections.sort(lista) (da classe Collections) e o método da própria lista, lista.sort(…).
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class Main {
public static void main(String[] args) {
List<String> alunos = new ArrayList<>();
alunos.add("Carla");
alunos.add("ana");
alunos.add("Bruno");
alunos.add("Álvaro");
alunos.add("Ana");
Collections.sort(alunos);
System.out.println("Collections.sort: " + alunos);
alunos.sort(Comparator.reverseOrder());
System.out.println("ordem inversa: " + alunos);
alunos.sort(String.CASE_INSENSITIVE_ORDER);
System.out.println("ignorando caixa: " + alunos);
List<Integer> notas = new ArrayList<>(List.of(7, 10, 3, 8));
notas.sort(null);
System.out.println("notas.sort(null): " + notas);
}
}
$ javac Main.java $ java Main Collections.sort: [Ana, Bruno, Carla, ana, Álvaro] « maiúsculas antes, acentos no fim ordem inversa: [Álvaro, ana, Carla, Bruno, Ana] ignorando caixa: [ana, Ana, Bruno, Carla, Álvaro] notas.sort(null): [3, 7, 8, 10]
- Collections.sort(alunos)
- Ordena a própria lista (não cria outra) em ordem natural: números do menor para o maior, textos pela tabela de caracteres.
- alunos.sort(Comparator.reverseOrder())
sortda lista recebe um comparador, um objeto que diz como comparar.reverseOrder()= ordem natural ao contrário.- String.CASE_INSENSITIVE_ORDER
- Um comparador pronto que ignora maiúsculas/minúsculas.
- notas.sort(null)
nullno lugar do comparador quer dizer "use a ordem natural". É o mesmo queCollections.sort(notas).
Por que ana ficou depois de Carla, e Álvaro por último? A ordem natural das Strings compara os códigos de cada caractere (veja char e boolean): todas as maiúsculas sem acento (A=65 … Z=90) vêm antes das minúsculas (a=97 … z=122), e as letras acentuadas (Á=193) vêm depois de todas elas. Para ordenar como num dicionário, ou por qualquer critério seu (nota, idade, tamanho do nome), você vai usar comparadores na aula Comparable e Comparator.
Brinque com o código: acrescente nomes, troque a ordem do sort, experimente Collections.reverse(nomes) e nomes.getFirst().
import java.util.*;
public class Main {
public static void main(String[] args) {
List<String> nomes = new ArrayList<>();
nomes.add("Duda");
nomes.add("Bruno");
nomes.add("Ana");
nomes.add(0, "Carla");
System.out.println("Lista: " + nomes);
Collections.sort(nomes);
System.out.println("Ordenada: " + nomes);
System.out.println("Primeiro: " + nomes.get(0));
System.out.println("Último: " + nomes.get(nomes.size() - 1));
}
}
Listas prontas e imutáveis: List.of
Quando você já sabe os elementos, List.of(…) cria a lista numa linha só. Mas ela é imutável: não aceita add, remove, set nem sort.
import java.util.List;
public class Main {
public static void main(String[] args) {
List<String> dias = List.of("seg", "ter", "qua", "qui", "sex");
System.out.println(dias + " tamanho " + dias.size());
System.out.println("get(2): " + dias.get(2));
dias.add("sáb");
}
}
$ javac Main.java $ java Main [seg, ter, qua, qui, sex] tamanho 5 get(2): qua Exception in thread "main" java.lang.UnsupportedOperationException at java.base/java.util.ImmutableCollections.uoe(ImmutableCollections.java:159) at java.base/java.util.ImmutableCollections$AbstractImmutableCollection.add(ImmutableCollections.java:164) at Main.main(Main.java:8)
Ler funciona; mudar dá UnsupportedOperationException ("operação não suportada"). Repare que o erro aparece só na hora de rodar: o compilador aceitou o add, porque o tipo da variável é List, e toda List tem add.
Isso é útil: uma lista que não pode ser alterada por engano. Quando você quer alterar, crie uma ArrayList a partir dela. O construtor new ArrayList<>(outraColecao) copia todos os elementos:
List<String> fixa = List.of("seg", "ter", "qua");
List<String> dias = new ArrayList<>(fixa);
dias.add("qui");
System.out.println("fixa: " + fixa);
System.out.println("dias: " + dias);
$ java Main fixa: [seg, ter, qua] dias: [seg, ter, qua, qui] « a cópia mudou; a original continua igual
Formas de criar uma lista
| Forma | Pode mudar? | Quando usar |
|---|---|---|
new ArrayList<>() + add | Sim | A lista vai sendo preenchida durante o programa (lida do teclado, de um arquivo…). |
List.of("a", "b") | Não | Valores fixos, conhecidos ao escrever o código. |
new ArrayList<>(List.of("a", "b")) | Sim | Começar com alguns valores e depois mudar. |
new ArrayList<>(outraLista) | Sim | Fazer uma cópia para mexer sem estragar a original. |
Quando dá errado
IndexOutOfBoundsException: posição que não existe
Este código tem um erro de propósito.
import java.util.ArrayList;
import java.util.List;
public class Main {
public static void main(String[] args) {
List<String> alunos = new ArrayList<>();
alunos.add("Ana");
alunos.add("Bruno");
alunos.add("Carla");
System.out.println("Último: " + alunos.get(alunos.size() - 1));
System.out.println(alunos.get(3));
}
}
$ javac Main.java $ java Main Último: Carla Exception in thread "main" java.lang.IndexOutOfBoundsException: Index 3 out of bounds for length 3 at java.base/jdk.internal.util.Preconditions.outOfBounds(Preconditions.java:100) at java.base/jdk.internal.util.Preconditions.outOfBoundsCheckIndex(Preconditions.java:106) at java.base/jdk.internal.util.Preconditions.checkIndex(Preconditions.java:302) at java.base/java.util.Objects.checkIndex(Objects.java:365) at java.base/java.util.ArrayList.get(ArrayList.java:428) at Main.main(Main.java:11)
O que quer dizer: "índice 3 fora dos limites para tamanho 3". Com 3 elementos, as posições válidas são 0, 1 e 2. O nome é parecido com o do array (ArrayIndexOutOfBoundsException), mas aqui é IndexOutOfBoundsException. A pilha (stack trace) mostra o caminho pela biblioteca; procure a primeira linha com o seu arquivo: Main.java:11.
Atenção à lista vazia: get(0) numa lista sem nada dá Index 0 out of bounds for length 0. Antes de ler, confira com isEmpty().
Como consertar: use posições de 0 a size() - 1, e laços com i < lista.size() (nunca <=).
UnsupportedOperationException: mexeu numa lista imutável
$ java Main Exception in thread "main" java.lang.UnsupportedOperationException at java.base/java.util.ImmutableCollections.uoe(ImmutableCollections.java:159) at java.base/java.util.ImmutableCollections$AbstractImmutableCollection.add(ImmutableCollections.java:164) at Main.main(Main.java:8)
O que quer dizer: a lista veio de List.of (ou de outro lugar que devolve listas imutáveis, como Collections.unmodifiableList e stream().toList()). A mensagem não tem texto: só o nome da exceção. A segunda linha diz qual operação foi recusada: .add.
Como consertar: faça uma cópia mutável: List<String> dias = new ArrayList<>(List.of(…));.
remove tirou o número errado (e não deu erro)
O que aconteceu: numa List<Integer>, remove(3) remove a posição 3, não o valor 3. Veja a pegadinha.
Como consertar: remove(Integer.valueOf(3)).
Referência
| Método | O que faz | Exemplo → resultado (lista [a, b, c]) |
|---|---|---|
add(x) | Acrescenta no fim | add("d") → [a, b, c, d] |
add(i, x) | Encaixa na posição i | add(0, "z") → [z, a, b, c] |
get(i) | Lê a posição i | get(1) → b |
set(i, x) | Troca a posição i; devolve o antigo | set(1, "B") → [a, B, c], devolve b |
remove(i) | Remove a posição i; devolve o removido | remove(0) → [b, c], devolve a |
remove(x) | Remove a 1ª ocorrência de x | remove("c") → [a, b], devolve true |
size() | Quantidade | 3 |
isEmpty() | Está vazia? | false |
contains(x) | Contém x? | contains("b") → true |
indexOf(x) / lastIndexOf(x) | Posição da 1ª / última ocorrência | indexOf("z") → -1 |
clear() | Apaga tudo | [] |
sort(null) / Collections.sort(l) | Ordem natural | — |
sort(Comparator.reverseOrder()) | Ordem inversa | [c, b, a] |
getFirst() / getLast() Java 21+ | Primeiro / último | a / c |
forEach(x -> …) | Faz algo com cada um | — |
List.of(…) | Lista pronta e imutável | — |
new ArrayList<>(col) | Cópia mutável de outra coleção | — |
Exercícios
1. O primeiro
Complete para ler o primeiro elemento da lista alunos:
2. Trocar sem aumentar
A posição 2 tem "feijão". Complete para trocar por "lentilha", sem mudar o tamanho da lista:
3. Remover o valor
Na List<Integer> notas, complete para remover o valor 8 (e não a posição 8):
4. A lista é [10, 20, 30] (de Integer). Como ela fica depois de remove(1)?
5. O que frutas.indexOf("kiwi") devolve se não houver kiwi?
6. List.of("a", "b").add("c")…
Missão final: o programa quebra porque a lista veio de List.of. Faça uma cópia mutável com new ArrayList<>(…); depois coloque "leite" no começo, remova "feijão", ordene e mostre a lista seguida do tamanho. A saída deve ser [arroz, café, leite] - 3 itens.
import java.util.ArrayList;
import java.util.List;
public class Main {
public static void main(String[] args) {
List<String> compras = List.of("arroz", "feijão", "café");
compras.add(0, "leite");
System.out.println(compras + " - " + compras.size() + " itens");
}
}
import java.util.ArrayList;
import java.util.List;
public class Main {
public static void main(String[] args) {
List<String> compras = new ArrayList<>(List.of("arroz", "feijão", "café"));
compras.add(0, "leite");
compras.remove("feijão");
compras.sort(null);
System.out.println(compras + " - " + compras.size() + " itens");
}
}
Resumo
List<String> l = new ArrayList<>();cria uma lista vazia que cresce sozinha. Posições começam em 0.add(x)põe no fim;add(i, x)encaixa;set(i, x)substitui;get(i)lê;size()conta.remove(i)remove por posição;remove(objeto)remove por valor e devolvetrue/false.- Em
List<Integer>,remove(3)é a posição 3; para o valor,remove(Integer.valueOf(3)). contains,indexOf(-1= não achou) eisEmptyprocuram; comparam comequals.- Percorra com for-each (o mais comum), com índice (quando precisa da posição) ou com
forEach. - Ordene com
Collections.sort(l)oul.sort(null); a ordem natural das Strings põe maiúsculas antes e acentos no fim. - Posição inválida:
IndexOutOfBoundsException. Mudar umaList.of:UnsupportedOperationException.
Próxima aula: LinkedList, a outra lista do Java, e quando (quase nunca) preferi-la.