1. Introdução
Na vida real, frequentemente nos deparamos com situações em que a cada “chave” única é preciso associar algum “valor”. Uma agenda telefônica armazena o número de telefone e o nome da pessoa; um dicionário associa uma palavra à sua tradução; e, em uma tabela de notas, cada estudante tem seu nome e a pontuação correspondente.
Em Java, há a interface Map para essas tarefas. É uma coleção que armazena pares “chave — valor” (key-value pair).
Propriedades principais de Map:
- Cada chave é única (não são permitidos duplicados).
- Uma chave pode corresponder a apenas um valor.
- Valores podem se repetir.
Vamos a uma analogia. Se uma lista (List) é como uma fila no refeitório (cada um tem sua posição; pode-se acessar pelo índice), então um mapa (Map) é como um armário com compartimentos: cada compartimento tem um número (chave) e dentro dele há algo específico (valor).
Interface Map: operações básicas
A interface Map declara os métodos principais para trabalhar com pares chave-valor:
| Método | Descrição |
|---|---|
|
Adicionar/substituir o valor pela chave |
|
Obter o valor pela chave |
|
Remover o par pela chave |
|
Verificar se existe tal chave |
|
Verificar se existe tal valor |
|
Quantidade de pares no mapa |
|
Verificar se o Map está vazio |
|
Remover todos os pares |
Os tipos K e V são parâmetros genéricos: K (Key) — tipo da chave, V (Value) — tipo do valor.
3. Classe HashMap: acesso rápido por chave
O que é HashMap?
HashMap é a implementação mais popular da interface Map. Ela fornece acesso rápido aos valores pela chave.
Importante: HashMap não garante a ordem de armazenamento dos elementos! Se você adicionou chaves em uma ordem específica, ao iterar elas podem vir em outra.
Como criar um HashMap?
import java.util.HashMap;
import java.util.Map;
public class Example {
public static void main(String[] args) {
// Criamos um mapa: chave — String, valor — Integer
Map<String, Integer> ages = new HashMap<>();
// Adicionamos elementos
ages.put("Vasya", 25);
ages.put("Petya", 30);
ages.put("Masha", 22);
// Obtemos o valor pela chave
int vasyaAge = ages.get("Vasya");
System.out.println("Idade do Vasya: " + vasyaAge); // 25
// Verificamos a existência da chave
if (ages.containsKey("Masha")) {
System.out.println("Masha está na lista!");
}
// Removemos um elemento
ages.remove("Petya");
// Iteramos todos os pares chave-valor
for (String name : ages.keySet()) {
System.out.println(name + ": " + ages.get(name));
}
}
}
Saída:
Idade do Vasya: 25
Masha está na lista!
Vasya: 25
Masha: 22
Particularidades do HashMap
O principal a lembrar: as chaves em HashMap são sempre únicas. Se você inserir um novo elemento com uma chave já existente, o valor antigo será substituído pelo novo.
Os valores podem se repetir: várias chaves diferentes podem apontar para o mesmo valor.
E mais um ponto importante — a ordem dos elementos. HashMap não se preocupa com a ordem de inserção. Ao imprimir, os registros podem aparecer embaralhados — isso é um comportamento normal.
4. Classe TreeMap: ordenação por chave
Ao contrário de HashMap, a classe TreeMap armazena os elementos em ordem ordenada pela chave.
Quando usar TreeMap?
Quando é importante que os elementos sigam a ordem crescente (ou decrescente) das chaves. Por exemplo, se você quiser imprimir uma agenda telefônica em ordem alfabética.
Exemplo:
import java.util.Map;
import java.util.TreeMap;
public class TreeMapExample {
public static void main(String[] args) {
Map<String, String> phoneBook = new TreeMap<>();
phoneBook.put("Vasya", "+1-900-123-45-67");
phoneBook.put("Masha", "+1-900-555-55-55");
phoneBook.put("Petya", "+1-900-222-33-44");
for (String name : phoneBook.keySet()) {
System.out.println(name + ": " + phoneBook.get(name));
}
}
}
Saída:
Masha: +1-900-555-55-55
Petya: +1-900-222-33-44
Vasya: +1-900-123-45-67
Observe: as chaves estão ordenadas alfabeticamente.
5. Operações básicas com Map
Adição e substituição de elementos
Map<String, Integer> scores = new HashMap<>();
scores.put("Anna", 90);
scores.put("Ivan", 85);
scores.put("Anna", 95); // Vai sobrescrever o valor de "Anna"
Obtenção de valor
Integer annaScore = scores.get("Anna"); // 95
Integer unknown = scores.get("Vasya"); // null, se essa chave não existir
Verificação da existência de chave ou valor
scores.containsKey("Ivan"); // true
scores.containsValue(85); // true
Remoção do par por chave
scores.remove("Ivan");
Tamanho do mapa e limpeza
int size = scores.size();
scores.clear(); // Remove todos os elementos
5. Iterando os elementos de Map
Map não é uma lista; não há índices aqui. Mas é possível iterar:
Pelas chaves:
for (String key : scores.keySet()) {
System.out.println("Chave: " + key + ", Valor: " + scores.get(key));
}
Pelos valores:
for (Integer value : scores.values()) {
System.out.println("Valor: " + value);
}
Por pares chave-valor (melhor maneira):
for (Map.Entry<String, Integer> entry : scores.entrySet()) {
String key = entry.getKey();
Integer value = entry.getValue();
System.out.println(key + " => " + value);
}
Quando usar HashMap e quando usar TreeMap?
HashMap é a opção “padrão” universal. Se a ordem das chaves não importa e o principal é a velocidade das operações, quase sempre usa-se ele.
TreeMap é útil quando você precisa de ordem. Ele mantém as chaves automaticamente ordenadas e permite encontrar rapidamente a chave mínima/máxima ou trabalhar com intervalos.
No geral: em 90% dos casos usamos HashMap. Quando os dados precisam já estar “em ordem”, use TreeMap.
6. Exemplos de uso de Map
Exemplo 1: Agenda telefônica
Map<String, String> phoneBook = new HashMap<>();
phoneBook.put("Katya", "+1-999-111-22-33");
phoneBook.put("Oleg", "+1-999-222-33-44");
phoneBook.put("Katya", "+1-999-555-66-77"); // O número antigo da Katya será substituído pelo novo
for (Map.Entry<String, String> entry : phoneBook.entrySet()) {
System.out.println(entry.getKey() + ": " + entry.getValue());
}
Saída:
Oleg: +1-999-222-33-44
Katya: +1-999-555-66-77
Exemplo 2: Contagem de palavras
Suponha que tenhamos uma lista de palavras e queremos saber quantas vezes cada palavra aparece:
import java.util.*;
public class WordCount {
public static void main(String[] args) {
List<String> words = Arrays.asList("maçã", "banana", "maçã", "pera", "banana", "maçã");
Map<String, Integer> counts = new HashMap<>();
for (String word : words) {
int oldCount = counts.getOrDefault(word, 0); // se a chave não existir — 0
counts.put(word, oldCount + 1);
}
System.out.println(counts); // {pera=1, maçã=3, banana=2}
}
}
7. Erros comuns ao trabalhar com Map
Erro nº 1: Confundir chaves e valores. Iniciantes frequentemente tentam obter um valor pelo índice, como em uma lista, ou esquecem que as chaves devem ser únicas. Em Map não há índices — apenas chaves.
Erro nº 2: Uso de chaves e valores null. Em HashMap é permitido usar a chave null, mas em TreeMap — não (lançará NullPointerException). Os valores podem ser null em ambas as implementações, mas isso raramente é útil.
Erro nº 3: Esperar ordem dos elementos em HashMap. HashMap não garante nenhuma ordem. Se precisar de ordem — use LinkedHashMap (preserva a ordem de inserção) ou TreeMap (ordena pela chave).
Erro nº 4: Modificar o Map durante a iteração. Se você estiver iterando um Map em um loop e, ao mesmo tempo, adicionando/removendo elementos, pode ocorrer ConcurrentModificationException. Para esses casos, use um iterador com o método remove() ou coleções especiais.
Erro nº 5: Comparar chaves e valores com == em vez de equals. Map usa o método equals para comparar chaves (e valores). Se você criar suas próprias classes-chave, sobrescreva equals e hashCode.
GO TO FULL VERSION