Ma

Mapas em Java

11 exercícios

Sobre Mapas

Um mapa é uma estrutura de dados para armazenar pares de chave-valor. É semelhante aos dicionários de outras linguagens de programação. A interface Map define as operações que podes realizar com um mapa.

HashMap

O Java tem várias implementações distintas de mapas. O HashMap é uma das mais utilizadas.

// Make an instance
Map<String, Integer> fruitPrices = new HashMap<>();
Note

Quando defines uma variável do tipo Map, recomenda-se que declares a variável como sendo do tipo Map em vez do tipo específico, como no exemplo acima. Esta prática facilita a alteração da implementação de Map mais tarde.

O HashMap também tem um construtor de cópia.

// Make a copy of a map
Map<String, Integer> copy = new HashMap<>(fruitPrices);

Adiciona entradas ao mapa com o método put.

fruitPrices.put("apple", 100);
fruitPrices.put("pear", 80);
// => { "apple" => 100, "pear" => 80 }

Só é possível associar um valor a cada chave. Se chamares put com a mesma chave, o valor dessa chave é atualizado.

fruitPrices.put("pear", 40);
// => { "apple" => 100, "pear" => 40 }

Usa o método get para obteres o valor de uma chave.

fruitPrices.get("apple"); // => 100

Usa o método containsKey para verificares se o mapa contém uma determinada chave.

fruitPrices.containsKey("apple");   // => true
fruitPrices.containsKey("orange");  // => false

Remove entradas com o método remove.

fruitPrices.put("plum", 90);  // Add plum to map
fruitPrices.remove("plum");   // Removes plum from map

O método size devolve o número de entradas.

fruitPrices.size();  // Returns 2

Podes usar os métodos keySet ou values para obteres as chaves ou os valores de um mapa sob a forma de um conjunto (Set) ou de uma coleção, respetivamente.

fruitPrices.keySet();  // Returns "apple" and "pear" in a set
fruitPrices.values();  // Returns 100 and 80, in a Collection

O HashMap usa hashCode e equals

O HashMap usa os métodos hashCode e equals do objeto para determinar onde armazenar os valores de uma chave e como os obter. Por este motivo, é importante que os valores devolvidos por esses métodos não mudem entre o momento de armazenar e o de obter, caso contrário o HashMap pode não conseguir encontrar o valor.

Por exemplo, digamos que temos a seguinte classe que será usada como chave de um mapa:

public class Stock {
    private String name;

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public int hashCode() {
        return Objects.hash(name);
    }

    @Override
    public boolean equals(Object obj) {
        if (obj == this) {
            return true;
        }
        if (Objects.equals(Stock.class, obj.getClass()) && obj instanceof Stock other) {
            return Objects.equals(name, other.name);
        }
        return false;
    }
}

O hashCode e o equals dependem do campo name, que pode ser alterado através de setName. Alterar o hashCode pode produzir resultados surpreendentes:

Stock stock = new Stock();
stock.setName("Beanies");

Map<Stock, Integer> stockCount = new HashMap<>();
stockCount.put(stock, 80);

stockCount.get(stock); // Returns 80

Stock other = new Stock();
other.setName("Beanies");

stockCount.get(other); // Returns 80 because "other" and "stock" are equal

stock.setName("Choccies");
stockCount.get(stock); // Returns null because hashCode value has changed

stockCount.get(other);  // Also returns null because "other" and "stock" are not equal

stock.setName("Beanies");
stockCount.get(stock); // HashCode restored, so returns 80 again

stockCount.get(other); // Also returns 80 again because "other" and "stock" are back to equal

Map.of e Map.copyOf

Outra forma comum de criar mapas é usar Map.of ou Map.ofEntries.

// Using Map.of
Map<String, Integer> temperatures = Map.of("Mon", 30, "Tue", 28, "Wed", 32);

// or using Map.ofEntries
Map<String, Integer> temperatures2 = Map.ofEntries(
    Map.entry("Mon", 30),
    Map.entry("Tue", 28),
    Map.entry("Wed", 32)
);

Ao contrário do HashMap, preenchem o mapa de antemão e tornam-se só de leitura depois de criados. O Map.copyOf cria uma cópia só de leitura de um mapa.

Map<String, Integer> readOnlyFruitPrices = Map.copyOf(fruitPrices);

Chamar métodos como put, remove ou clear provoca uma UnsupportedOperationException.

Editar via GitHub A ligação abre numa nova janela ou separador

Aprende Mapas

A prática está bloqueada

Desbloqueia mais 1 exercício para praticares Mapas