Map e HashMap

Map é uma coleção de pares chave-valor. Esta lição cobre o uso de Map.

Características da Interface Map

Característica Descrição
Pares chave-valor Cada elemento contém uma chave e um valor
Chaves únicas Chaves são únicas, valores podem se repetir
Não ordenada HashMap não é ordenado

HashMap

HashMap é a implementação de Map mais comumente usada.

Criando HashMap

JAVA
import java.util.HashMap;
import java.util.Map;

Map<String, Integer> map1 = new HashMap<>();
Map<String, Integer> map2 = new HashMap<>(100);  // Capacidade especificada
Map<String, Integer> map3 = new HashMap<>(map1);  // De outro Map

Operações Básicas

JAVA
import java.util.HashMap;
import java.util.Map;

public class HashMapDemo {
    public static void main(String[] args) {
        Map<String, Integer> scores = new HashMap<>();
        
        // Adicionar pares chave-valor
        scores.put("Alice", 95);
        scores.put("Bob", 88);
        scores.put("Charlie", 92);
        System.out.println("Map: " + scores);
        
        // Obter valor
        int aliceScore = scores.get("Alice");
        System.out.println("Pontuação de Alice: " + aliceScore);
        
        // Obter valor (retorna padrão se chave não existe)
        int davidScore = scores.getOrDefault("David", 0);
        System.out.println("Pontuação de David: " + davidScore);
        
        // Verificar
        System.out.println("Contém Alice: " + scores.containsKey("Alice"));
        System.out.println("Contém 95: " + scores.containsValue(95));
        System.out.println("Tamanho: " + scores.size());
        
        // Modificar
        scores.put("Alice", 98);  // Sobrescrever valor antigo
        System.out.println("Alice atualizada: " + scores.get("Alice"));
        
        // Remover
        scores.remove("Bob");
        System.out.println("Após remover: " + scores);
    }
}

putIfAbsent

JAVA
Map<String, Integer> map = new HashMap<>();
map.put("Alice", 95);

// Adicionar apenas se chave não existe
map.putIfAbsent("Alice", 100);  // Não vai sobrescrever
map.putIfAbsent("Bob", 88);     // Vai adicionar

System.out.println(map);  // {Alice=95, Bob=88}

Métodos de Travessia

Método 1: Percorrer keySet

JAVA
Map<String, Integer> map = new HashMap<>();
map.put("Alice", 95);
map.put("Bob", 88);
map.put("Charlie", 92);

for (String key : map.keySet()) {
    System.out.println(key + ": " + map.get(key));
}

Método 2: Percorrer values

JAVA
for (int value : map.values()) {
    System.out.println(value);
}

Método 3: Percorrer entrySet

JAVA
for (Map.Entry<String, Integer> entry : map.entrySet()) {
    System.out.println(entry.getKey() + ": " + entry.getValue());
}

Método 4: Lambda

JAVA
map.forEach((key, value) -> System.out.println(key + ": " + value));

Exemplo: Travessia de Map

JAVA
import java.util.HashMap;
import java.util.Map;

public class MapTraversal {
    public static void main(String[] args) {
        Map<String, Integer> scores = new HashMap<>();
        scores.put("Alice", 95);
        scores.put("Bob", 88);
        scores.put("Charlie", 92);
        
        // Percorrer entrySet
        System.out.println("=== Travessia entrySet ===");
        for (Map.Entry<String, Integer> entry : scores.entrySet()) {
            System.out.println(entry.getKey() + ": " + entry.getValue());
        }
        
        // Travessia Lambda
        System.out.println("=== Travessia Lambda ===");
        scores.forEach((name, score) -> 
            System.out.println(name + "'s score is " + score));
    }
}
▶ Experimente

TreeMap

TreeMap é baseado em árvore rubro-negra e as chaves são automaticamente ordenadas.

Exemplo: TreeMap

JAVA
import java.util.Map;
import java.util.TreeMap;

public class TreeMapDemo {
    public static void main(String[] args) {
        Map<String, Integer> map = new TreeMap<>();
        map.put("Charlie", 92);
        map.put("Alice", 95);
        map.put("Bob", 88);
        
        // Ordenado por chave
        map.forEach((key, value) -> 
            System.out.println(key + ": " + value));
        // Alice: 95
        // Bob: 88
        // Charlie: 92
    }
}
▶ Experimente

LinkedHashMap

LinkedHashMap mantém a ordem de inserção.

Exemplo: LinkedHashMap

JAVA
import java.util.LinkedHashMap;
import java.util.Map;

public class LinkedHashMapDemo {
    public static void main(String[] args) {
        Map<String, Integer> map = new LinkedHashMap<>();
        map.put("Charlie", 92);
        map.put("Alice", 95);
        map.put("Bob", 88);
        
        // Ordem de inserção
        map.forEach((key, value) -> 
            System.out.println(key + ": " + value));
        // Charlie: 92
        // Alice: 95
        // Bob: 88
    }
}
▶ Experimente

Métodos Comuns de Map

Método Descrição
put(K, V) Adicionar par chave-valor
get(K) Obter valor
getOrDefault(K, V) Obter valor, retornar padrão se não existe
putIfAbsent(K, V) Adicionar se chave não existe
remove(K) Remover par chave-valor
containsKey(K) Contém chave
containsValue(V) Contém valor
keySet() Todas as chaves como Set
values() Todos os valores como Collection
entrySet() Todas as entradas como Set
size() Tamanho
isEmpty() Está vazio
clear() Limpar tudo
putAll(Map) Adicionar todos

Comparação de Map

Característica HashMap TreeMap LinkedHashMap
Ordem Não ordenada Ordenada Ordem de inserção
Implementação Tabela hash Árvore rubro-negra Lista ligada + tabela hash
Performance O(1) O(log n) O(1)
Chave null 1 permitido Não permitido 1 permitido

Exemplo: Contador de Frequência de Palavras

JAVA
import java.util.HashMap;
import java.util.Map;

public class WordCount {
    public static Map<String, Integer> count(String text) {
        Map<String, Integer> map = new HashMap<>();
        String[] words = text.toLowerCase().split("\\s+");
        
        for (String word : words) {
            map.put(word, map.getOrDefault(word, 0) + 1);
        }
        
        return map;
    }
    
    public static void main(String[] args) {
        String text = "hello world hello java world hello";
        Map<String, Integer> counts = count(text);
        
        counts.forEach((word, count) -> 
            System.out.println(word + ": " + count));
        // hello: 3
        // world: 2
        // java: 1
    }
}

Exemplo: Agrupamento

JAVA
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class GroupBy {
    public static Map<String, List<String>> groupByFirstChar(List<String> list) {
        Map<String, List<String>> map = new HashMap<>();
        
        for (String s : list) {
            String key = s.substring(0, 1).toUpperCase();
            map.computeIfAbsent(key, k -> new ArrayList<>()).add(s);
        }
        
        return map;
    }
    
    public static void main(String[] args) {
        List<String> names = new ArrayList<>();
        names.add("Alice");
        names.add("Bob");
        names.add("Charlie");
        names.add("David");
        names.add("Eve");
        
        Map<String, List<String>> groups = groupByFirstChar(names);
        groups.forEach((key, value) -> 
            System.out.println(key + ": " + value));
        // A: [Alice]
        // B: [Bob]
        // C: [Charlie]
        // D: [David]
        // E: [Eve]
    }
}

❓ Perguntas Frequentes

P: Chaves do HashMap podem ser nulas? R: Sim, apenas uma chave nula permitida. Valores podem ter múltiplos nulos.

P: Como o HashMap detecta chaves duplicadas? R: Primeiro compara hashCode, depois compara equals, semelhante ao HashSet.

P: HashMap é thread-safe? R: Não. Use ConcurrentHashMap para cenários multi-threaded.

📖 Resumo

📝 Exercícios

  1. Frequência de palavras: Conte as ocorrências de cada palavra em uma string
  2. Agrupamento: Agrupe estudantes por nível de nota (Excelente/Bom/Aprovado/Reprovado)
  3. Cache: Implemente um cache simples usando HashMap

Próxima Lição

Na próxima lição, aprenderemos sobre Generics — entendendo generics em Java.

100%