Java Cola de Coleções
Uma página para consultar quando você precisar escolher uma coleção ou lembrar o nome de um método. Primeiro a tabela "qual usar", depois os métodos de List, Set, Map e Deque, com exemplos e resultados reais do JShell. Para aprender cada uma com calma, comece pela Visão Geral das Coleções.
- Interfaces × implementações: ordem, duplicados,
nulle velocidade. - A mesma lista em cada coleção, para ver as diferenças.
- Métodos de List, Set, Map e Deque.
- Coleções imutáveis (
List.of,Map.of) e os erros mais comuns.
Todos os exemplos começam com import java.util.*. Na hora de declarar, use a interface à esquerda e a implementação à direita: List<String> nomes = new ArrayList<>();. Assim, trocar de implementação depois é mudar uma palavra.
Qual coleção usar
| Interface | Implementação | Ordem | Duplicados | null | Buscar / inserir | Use quando… |
|---|---|---|---|---|---|---|
Listsequência com posições | ArrayList | de inserção (por índice) | sim | sim | get(i) O(1); add no fim O(1)*; inserir/remover no meio O(n); contains O(n) | Quase sempre que precisar de uma lista. É a escolha padrão. |
LinkedList | de inserção | sim | sim | get(i) O(n); inserir/remover nas pontas O(1) | Raramente; para filas e pilhas, prefira ArrayDeque. | |
Setsem repetidos | HashSet | nenhuma garantida | não | um | add/contains/remove O(1) em média | Saber rápido "já tem?", eliminar repetidos. |
LinkedHashSet | de inserção | não | um | O(1) em média | Sem repetidos, mas lembrando a ordem em que entraram. | |
TreeSet | ordenada (natural ou Comparator) | não | não | O(log n) | Sem repetidos e sempre em ordem; menor, maior, "o próximo depois de x". | |
Mapchave → valor | HashMap | nenhuma garantida | chaves não; valores sim | uma chave, valores sim | get/put/containsKey O(1) em média | Achar algo pela chave: dicionário, cadastro por código, contagem. |
LinkedHashMap | de inserção | chaves não | sim | O(1) em média | Como o HashMap, mas a listagem sai na ordem de inserção. | |
TreeMap | ordenada pela chave | chaves não | chave não; valores sim | O(log n) | Mapa sempre em ordem de chave; faixas de chaves. | |
Deque / Queuepontas | ArrayDeque | de inserção | sim | não | pôr/tirar nas pontas O(1) | Pilha (push/pop) ou fila (offer/poll). |
PriorityQueue | sai sempre o menor (ou o de maior prioridade) | sim | não | offer/poll O(log n); peek O(1) | Processar por prioridade: tarefas urgentes primeiro, menor caminho. |
O(1) = tempo constante, não importa o tamanho; O(log n) = cresce muito devagar (1 milhão de itens ≈ 20 passos); O(n) = proporcional ao tamanho (percorre tudo). * Amortizado: de vez em quando o ArrayList precisa crescer e copia tudo, mas na média continua O(1).
Lista: ArrayList. Sem repetidos: HashSet. Chave → valor: HashMap. Precisa de ordem? Troque por TreeSet/TreeMap (ordenado) ou LinkedHashSet/LinkedHashMap (ordem de inserção). Pilha ou fila: ArrayDeque.
A mesma lista em cada coleção
Cinco frutas, com maçã repetida, copiadas para cada tipo de coleção:
$ jshell
| Welcome to JShell -- Version 25.0.4.1
| For an introduction type: /help intro
jshell> import java.util.*
jshell> var frutas = List.of("uva", "maçã", "banana", "kiwi", "maçã")
frutas ==> [uva, maçã, banana, kiwi, maçã]
jshell> new ArrayList<>(frutas)
$3 ==> [uva, maçã, banana, kiwi, maçã]
jshell> new LinkedList<>(frutas)
$4 ==> [uva, maçã, banana, kiwi, maçã]
jshell> new HashSet<>(frutas)
$5 ==> [banana, uva, kiwi, maçã]
jshell> new LinkedHashSet<>(frutas)
$6 ==> [uva, maçã, banana, kiwi]
jshell> new TreeSet<>(frutas)
$7 ==> [banana, kiwi, maçã, uva]
As listas guardam tudo, na ordem. Os conjuntos tiram a maçã repetida: o HashSet numa ordem própria (que pode mudar de uma versão do Java para outra), o LinkedHashSet na ordem de chegada e o TreeSet em ordem alfabética.
Experimente: elimine os repetidos e ordene ao mesmo tempo: crie um TreeSet a partir de List.of(5, 3, 8, 3, 1, 5).
new java.util.TreeSet<>(java.util.List.of(5, 3, 8, 3, 1, 5))
Métodos de List
Valem para ArrayList e LinkedList. Os exemplos rodam em sequência, começando com var l = new ArrayList<>(List.of("Ana", "Bia", "Caio")); cada linha parte do resultado da anterior.
| Método | O que faz | Exemplo | Resultado |
|---|---|---|---|
boolean add(E e) | Põe no fim. | l.add("Duda") | true |
void add(int i, E e) | Põe na posição i, empurrando os outros. | l.add(1, "Beto") | l = [Ana, Beto, Bia, Caio, Duda] |
E get(int i) | O item da posição. | l.get(0) | "Ana" |
E set(int i, E e) | Troca o item da posição; devolve o antigo. | l.set(0, "Aline") | "Ana" |
int indexOf(Object o) | Posição da primeira ocorrência, ou -1. | l.indexOf("Caio") | 3 |
boolean contains(Object o) | Tem esse item? (usa equals) | l.contains("Bia") | true |
boolean remove(Object o) | Remove a primeira ocorrência do item. | l.remove("Beto") | true |
E remove(int i) | Remove a posição; devolve o removido. | l.remove(0) | "Aline" |
int size() | Quantos itens. | l.size() | 3 ([Bia, Caio, Duda]) |
boolean isEmpty() | Está vazia? | l.isEmpty() | false |
List<E> subList(int de, int até) | Um pedaço [de, até) (uma "janela" para a lista original). | l.subList(0, 2) | [Bia, Caio] |
void sort(Comparator c) | Ordena a própria lista. | l.sort(Comparator.reverseOrder()) | l = [Duda, Caio, Bia] |
boolean removeIf(Predicate p) | Remove todos que cumprem a condição (lambda). | l.removeIf(n -> n.startsWith("C")) | true; l = [Duda, Bia] |
boolean addAll(Collection c) | Põe todos os itens de outra coleção no fim. | l.addAll(List.of("Eva", "Fábio")) | true; l = [Duda, Bia, Eva, Fábio] |
void clear() | Esvazia. | l.clear(); l.size() | 0 |
Collections.sort(lista) | Ordena em ordem natural (forma antiga de l.sort(null)). Veja A Classe Collections. | Collections.sort(l) | [Bia, Caio, Duda] |
remove(1) numa List<Integer>
Remove a posição 1, não o número 1. Para remover o valor, escreva lista.remove(Integer.valueOf(1)). Veja ArrayList.
Métodos de Set
Começando com var s = new HashSet<>(Set.of(1, 2, 3)):
| Método | O que faz | Exemplo | Resultado |
|---|---|---|---|
boolean add(E e) | Põe o item; devolve false se já existia (e não faz nada). | s.add(2)s.add(4) | falsetrue |
boolean contains(Object o) | Tem? (rápido: O(1) no HashSet) | s.contains(3) | true |
boolean remove(Object o) | Tira o item. | s.remove(1) | true |
int size() | Quantos itens. | s.size() | 3 |
addAll(c) | União: junta os itens de outra coleção. | {1, 2} .addAll(Set.of(2, 3)) | [1, 2, 3] |
retainAll(c) | Interseção: fica só com o que também está na outra. | {1, 2, 3, 4, 5} .retainAll(Set.of(2, 4, 6)) | [2, 4] |
removeAll(c) | Diferença: tira o que está na outra. | {1, 2, 3} .removeAll(Set.of(2)) | [1, 3] |
Só no TreeSet (ordenado), com var t = new TreeSet<>(Set.of(10, 5, 20, 15)):
| Método | O que faz | Exemplo | Resultado |
|---|---|---|---|
E first() / E last() | O menor / o maior. | t.first()t.last() | 520 |
E ceiling(E e) | O menor que seja ≥ e (floor: o maior ≤ e). | t.ceiling(12) | 15 |
SortedSet headSet(E até) | Os menores que até (tailSet: os ≥). | t.headSet(15) | [5, 10] |
Métodos de Map
Começando com var m = new HashMap<String, Integer>() (nome → nota):
| Método | O que faz | Exemplo | Resultado |
|---|---|---|---|
V put(K chave, V valor) | Guarda. Se a chave já existia, substitui e devolve o valor antigo; senão devolve null. | m.put("Ana", 8)m.put("Bia", 9)m.put("Ana", 10) | nullnull8 |
V get(Object chave) | O valor da chave, ou null se não existe. | m.get("Ana")m.get("Zé") | 10null |
V getOrDefault(chave, padrão) | Como get, mas com um valor padrão no lugar de null. | m.getOrDefault("Zé", 0) | 0 |
boolean containsKey(chave) | Essa chave existe? (rápido) | m.containsKey("Bia") | true |
boolean containsValue(valor) | Algum valor é igual? (percorre tudo: O(n)) | m.containsValue(9) | true |
V putIfAbsent(chave, valor) | Só guarda se a chave não existir; devolve o valor atual. | m.putIfAbsent("Bia", 0) | 9 (não mudou) |
V merge(chave, valor, função) | Se a chave não existe, guarda o valor; se existe, junta com a função. O jeito curto de contar. | m.merge("Caio", 1, Integer::sum)(de novo) | 12 |
V remove(chave) | Tira a chave; devolve o valor que estava. | m.remove("Bia") | 9 |
Set<K> keySet() | As chaves. | m.keySet() | [Ana, Caio] |
Collection<V> values() | Os valores. | m.values() | [10, 2] |
Set<Map.Entry<K,V>> entrySet() | Os pares chave=valor, para percorrer com for (var e : m.entrySet()) e usar e.getKey()/e.getValue(). | new TreeMap<>(m).entrySet() | [Ana=10, Caio=2] |
int size() | Quantos pares. | m.size() | 2 |
new TreeMap<>(mapa) | Uma cópia ordenada pela chave (para mostrar em ordem). | new TreeMap<>(m) | {Ana=10, Caio=2} |
Só no TreeMap, com var tm = new TreeMap<>(Map.of("c", 3, "a", 1, "b", 2)): tm.firstKey() → "a"; tm.headMap("c") → {a=1, b=2} (as chaves menores que "c"). Também existem lastKey, tailMap, ceilingKey e floorKey.
Missão: conte quantas vezes cada fruta aparece usando um TreeMap<String, Integer> e merge(fruta, 1, Integer::sum). O resultado deve ser {banana=1, kiwi=1, maçã=2, uva=1}.
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
public class Main {
public static void main(String[] args) {
List<String> frutas = List.of("uva", "maçã", "banana", "kiwi", "maçã");
Map<String, Integer> contagem = new TreeMap<>();
// conte cada fruta aqui
System.out.println(contagem);
}
}
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
public class Main {
public static void main(String[] args) {
List<String> frutas = List.of("uva", "maçã", "banana", "kiwi", "maçã");
Map<String, Integer> contagem = new TreeMap<>();
for (String fruta : frutas) {
contagem.merge(fruta, 1, Integer::sum);
}
System.out.println(contagem);
}
}
Métodos de Deque (pilha e fila)
Deque (double-ended queue, "fila de duas pontas") põe e tira itens nas duas pontas. Com var d = new ArrayDeque<String>():
| Uso | Método | O que faz | Exemplo | Resultado |
|---|---|---|---|---|
| Pilha (o último a entrar sai primeiro) | void push(E e) | Empilha no topo (a frente). | d.push("prato 1")d.push("prato 2") | d = [prato 2, prato 1] |
E peek() | Olha o topo sem tirar (null se vazia). | d.peek() | "prato 2" | |
E pop() | Tira do topo. Vazia: NoSuchElementException. | d.pop() | "prato 2" | |
| Fila (o primeiro a entrar sai primeiro) | boolean offerLast(E e) / offer | Entra no fim da fila. | d.offerLast("fila 1") | true |
boolean offerFirst(E e) | Entra na frente (fura a fila). | d.offerFirst("frente") | d = [frente, prato 1, fila 1] | |
E pollFirst() / poll | Tira da frente. Vazia: null. | d.pollFirst()new ArrayDeque<String>().poll() | "frente"null | |
| Fim | E pollLast() | Tira do fim. | d.pollLast() | "fila 1"; d = [prato 1] |
| Prioridade | PriorityQueue.poll() | Sai sempre o menor, não importa a ordem de entrada. | new PriorityQueue<>(List.of(5, 1, 4, 2)), poll() duas vezes | 1, depois 2 |
Cada operação de fila existe em duas versões: uma lança exceção quando não dá (add, remove, element, pop) e outra devolve false/null (offer, poll, peek). Para filas que podem ficar vazias, prefira a segunda e confira o null.
Coleções imutáveis
List.of(…), Set.of(…) e Map.of(…) Java 9+ criam coleções prontas que não podem ser alteradas. Ótimas para dados fixos; para uma lista que vai mudar, copie: new ArrayList<>(List.of(…)). stream().toList() Java 16+ também devolve uma lista imutável.
| Forma | Pode mudar? | Aceita null? |
|---|---|---|
new ArrayList<>(), new HashMap<>()… | sim | sim (exceto Tree… e ArrayDeque) |
List.of, Set.of, Map.of, stream().toList() | não | não |
Arrays.asList(array) | pode trocar itens (set), não pode mudar o tamanho | sim |
Collections.unmodifiableList(l) | não (mas é uma "janela" para l: se l mudar, ela muda) | sim |
Quando dá errado
As mensagens reais, no JShell:
| Código | Exceção | Por quê |
|---|---|---|
List.of(1, 2).add(3) | UnsupportedOperationException | Coleção imutável. |
List.of("a", null) | NullPointerException | List.of não aceita null. |
Map.of("a", 1, "a", 2) | IllegalArgumentException: duplicate key: a | Chave repetida em Map.of. |
new TreeSet<String>().add(null) | NullPointerException: Cannot invoke "java.lang.Comparable.compareTo(Object)" because "k1" is null | O TreeSet/TreeMap precisa comparar, e null não se compara. |
new ArrayDeque<String>().add(null) | NullPointerException | ArrayDeque usa null internamente para "vazio". |
new ArrayDeque<String>().pop() | NoSuchElementException | Pilha vazia (use poll para receber null). |
lista.get(5) com 3 itens | IndexOutOfBoundsException: Index 5 out of bounds for length 3 | Posição inexistente. |
| Remover dentro de um for-each | ConcurrentModificationException | A lista mudou durante o laço; use removeIf ou um Iterator. |
$ jshell
| Welcome to JShell -- Version 25.0.4.1
| For an introduction type: /help intro
jshell> List.of(1, 2).add(3)
| Exception java.lang.UnsupportedOperationException
| at ImmutableCollections.uoe (ImmutableCollections.java:159)
| at ImmutableCollections$AbstractImmutableCollection.add (ImmutableCollections.java:164)
| at (#1:1)
jshell> Map.of("a", 1, "a", 2)
| Exception java.lang.IllegalArgumentException: duplicate key: a
| at ImmutableCollections$MapN.<init> (ImmutableCollections.java:1440)
| at Map.of (Map.java:1384)
| at (#2:1)
Mais detalhes sobre cada exceção em Exceções Comuns.
Exercícios
1. Você precisa guardar os e-mails já cadastrados e perguntar muitas vezes "este já existe?". Qual coleção?
2. O que m.put("Ana", 10) devolve se "Ana" já valia 8?
3. Qual destas coleções aceita null?
Complete para criar um mapa que lista as chaves em ordem alfabética:
Resumo
List= sequência com posições e repetidos;Set= sem repetidos;Map= chave → valor;Deque= pilha e fila.Hash…: rápido, sem ordem;Linked…: ordem de inserção;Tree…: ordenado, O(log n), semnull.- Padrões:
ArrayList,HashSet,HashMap,ArrayDeque. Declare pela interface. List.of/Set.of/Map.ofsão imutáveis e recusamnull.