1. Introdução
Os objetos Map processam seus dados em um algoritmo hash (hash code). Esse algoritmo transforma uma grande quantidade de dados em uma pequena quantidade de informações, sendo que o mecanismo de busca se baseia na construção de índices.
Um exemplo prático pode ser usado como uma lista telefônica onde a letra seria o índice a ser procurado, para conseguir achar mais fácil o nome desejado.


Figura 1. Exemplo do mecanismo do algoritmo hash, primeiro os dados serão agrupados em conjuntos que apresentam a mesma propriedade e depois serão identificados os dados indivídualmente. Observe que a busca pelo dado será bem mais rápida, não há necessidade de verificar toda a lista, primeiro verifica se o dado esta dentro de um grupo de valores e depois procura-se o dado dentro desse grupo, descarta-se assim, a procura nos demais grupos da primeira verificação.

2. Interface Map
Essa interface é um objeto que mapeia valores para chaves, ou seja, através da chave consegue-se o acesso do valor configurado, sendo que a chave não pode ser repetida ao contrário do valor, mas se caso tiver uma chave repetida é sobrescrito pela última chamada. Também faz parte do pacote “java.util” e não possui métodos da interface Collection.

Na Figura 2, consegue-se visualizar quais classes podem ser implementadas pela interface Map.

Figura 2. Hierarquia da interface Map.

A sintaxe deve obedecer os lugares apontados da chave e valor, pois cada chave leva somente um elemento, segue um exemplo abaixo:
Sintaxe:
Map<E> mapa = new Type();
E: é o objeto declarado, podendo ser classes Wrappers ou tipo de coleção.
Type: é o tipo de objeto da coleção a ser usado.

O Map interface fornece um conjunto de métodos que devem ser implementados. Os métodos mais comuns são:

clear: Remove todos os elementos do mapa.
containsKey: Retorna true se o mapa contém a chave solicitada.
containsValue: Retorna true se o mapa contém o valor solicitado.
equals: Compara um objeto com o mapa para a igualdade.
get: Recuperar o valor da chave solicitada.
keySet: Retorna um conjunto que contém todas as chaves do mapa.
put: Adiciona o par chave-valor solicitado no mapa.
remove: Remove a chave solicitada e seu valor a partir do mapa, se a chave existe.
size: Retorna o número de pares chave-valor atualmente no mapa.

Exemplo de atribuição e impressão de valores.

import java.util.HashMap;
import java.util.Map;
 
public class TestaInterfaceMap {
 
    public static void main(String[] args) {
    
        Map<Integer, String> mapaNomes = new HashMap<Integer, String>();
        mapaNomes.put(1, "João Delfino");
        mapaNomes.put(2, "Maria do Carmo");
        mapaNomes.put(3, "Claudinei Silva");
 
        System.out.println(mapaNomes);
        
        //resgatando o nome da posição 2
        System.out.println(mapaNomes.get(2));
        
    }
}

Execução:
{1=João Delfino, 2=Maria do Carmo, 3=Claudinei Silva}
Maria do Carmo

3. Classe HashMap
A classe mais comum que implementa a interface Map é a HashMap . Uma classe  HashMap é uma implementação baseada em tabela hash da interface Map. Ela permite chaves e valores nulos. Além disso, esta classe não mantém qualquer ordem entre seus elementos e, principalmente, ela não garante que a ordem permanecerá constante ao longo do tempo.
Em realidade, a classe HashMap é bem similar à classe HashTable, com a diferença que HashMap não é sincronizada, ou seja, múltiplos threads podem alterar o mapeamento concorrentemente (tenha cuidado ao usuá-la em ambiente de múltiplas threads) e permite valores e chaves null.
Finalmente, um HashMap contém dois parâmetros fundamentais: capacidade inicial e desempenho. A capacidade é definida como o número de "baldes" na tabela de hash, enquanto a taxa de ocupação é uma medida que indica o valor máximo a tabela hash pode alcançar, antes de ser automaticamente aumentado.
Embora a classe seja uma implementação da interface Map, porém ela é mais trabalhada no campo de desenvolvimento.

Características:
Os elementos não são ordenados.
É rápida na busca/inserção de dados.
Permite inserir valore e chaves nulas.
Sintaxe:

HashMap mapa = new Type();
Type: é o tipo de objeto da coleção a ser usado.

Métodos úteis
Esses métodos oferece bastante ajuda quando é trabalhado com a interface Map.
values() - É uma Collection com todos os valores que foram associados as chaves.
keySet() - Retorna um Set com as chaves do mapa especificado.
entrySet() - Retorna um conjunto de Maps contido no mapa configurado, podendo ser possível acessar suas chaves e valores.
put(Key key, Value value) - Associa um valor a uma chave específica.

Para interagir com um mapa é preciso trabalhar com a interface Collection ou métodos set() para converter esse mapa em um conjunto de dados.


Veja a posição da classe HashMap na hierarquia de classes Java:

java.lang.Object
  java.util.AbstractMap<K,V>
    java.util.HashMap<K,V>

Esta classe implementa ainda as interfaces Serializable, Cloneable e Map<K,V>. Algumas sub-classes conhecidas são LinkedHashMap e PrinterStateReasons.

O uso principal da classe HashMap é quando queremos associar chaves e valores e, posteriormente, recuperar valores baseados em suas chaves.


A classe HashMap suporta quatro construtores:

A primeira forma constrói um mapa hash padrão.
HashMap( )
A segunda forma inicializa o mapa hash, utilizando os elementos de m:
HashMap(Map m)
A terceira forma inicializa a capacidade do mapa hash:
HashMap(int capacity)
A quarta forma inicializa tanto a capacidade como preencher as proporções do mapa hash usando seus argumentos:
HashMap(int capacity, float fillRatio)

Além dos métodos herdados de suas classes pai, HashMap define os seguintes métodos:
SNMethods with Description
1void clear() 
Remove todos os mapeamentos a partir deste mapa.
2Object clone() 
Retorna uma cópia superficial desta instância HashMap: as chaves e valores em si não são clonados.
3boolean containsKey(Object key) 
Retorna true se o mapa contém um mapeamento para a chave especificada.
4boolean containsValue(Object value) 
Retorna true se o mapa mapas uma ou mais chaves para o valor especificado.
5Set entrySet() 
Retorna uma visão de coleção dos mapeamentos contidos neste mapa.
6Object get(Object key) 
Retorna o valor para o qual a chave especificada está mapeada neste mapa de hash de identidade, ou nulo se o mapa contém nenhum mapeamento para esta chave.
7boolean isEmpty()
Retorna true se o mapa não contém mapeamentos chave-valor.
8Set keySet() 
Retorna uma exibição conjunto das chaves contidas neste mapa.
9Object put(Object key, Object value)
Associa o valor especificado com a chave especificada neste mapa.
10putAll(Map m) 
Copia todos os mapeamentos do mapa especificado para este mapa Esses mapeamentos substituirão quaisquer mapeamentos que este mapa tinha para qualquer uma das teclas atualmente no mapa especificado.
11Object remove(Object key) 
Remove o mapeamento para esta chave a partir deste mapa se estiver presente.
12int size() 
Retorna o número de mapeamentos chave-valor neste mapa.
13Collection values() 
Retorna uma visão de coleção dos valores contidos neste mapa.

Iterator
O iterator é uma interface disponível no pacote java.util que permite percorrer coleções da API Collection, desde que tenham implementado a Collection, fornecendo métodos como o next(), hasnext() e remove().

Exemplo de Iterator:

List<Integer> minhaLista = new ArrayList<Integer>();
        minhaLista.add(1);
        minhaLista.add(2);
        Iterator iMinhaLista = minhaLista.iterator();

        for(Integer listaElementos: minhaLista){
            System.out.println(iMinhaLista.next());
        }

Exemplo:

import java.util.*;

public class HashMapDemo {

   public static void main(String args[]) {
  
      // Create a hash map
      HashMap hm = new HashMap();
      // Put elements to the map
      hm.put("Zara", new Double(3434.34));
      hm.put("Mahnaz", new Double(123.22));
      hm.put("Ayan", new Double(1378.00));
      hm.put("Daisy", new Double(99.22));
      hm.put("Qadir", new Double(-19.08));
     
      // Get a set of the entries
      Set set = hm.entrySet();
      // Get an iterator
      Iterator i = set.iterator();
      // Display elements
      while(i.hasNext()) {
         Map.Entry me = (Map.Entry)i.next();
         System.out.print(me.getKey() + ": ");
         System.out.println(me.getValue());
      }
      System.out.println();
      // Deposit 1000 into Zara's account
      double balance = ((Double)hm.get("Zara")).doubleValue();
      hm.put("Zara", new Double(balance + 1000));
      System.out.println("Zara's new balance: " + hm.get("Zara"));
   }
}


Zara: 3434.34
Mahnaz: 123.22
Daisy: 99.22
Ayan: 1378.0
Qadir: -19.08

Zara's new balance: 4434.34

Obs: Como obter o valor de uma chave?
(Tipo)mapa.get("key").tipoValue()
(Tipo) tranforma o objeto mapa no tipo do valor.


Veja um exemplo no qual temos cidades e habitantes:

import java.util.*;

public class Estudos{
  @SuppressWarnings("unchecked")
  public static void main(String[] args){
   
    // cria uma nova instância de HashMap
    HashMap cidadesHabitantes = new HashMap();
   
    // vamos adicionar algumas chaves e seus valores
    cidadesHabitantes.put("Goiânia", new Integer(4334598));
    cidadesHabitantes.put("São Paulo", new Integer(49282768));
    cidadesHabitantes.put("Brasília", new Integer(96736887));  
 
    // vamos obter uma view dos mapeamentos
    Set set = cidadesHabitantes.entrySet();

    // obtemos um iterador
    Iterator i = set.iterator();

    // e finalmente exibimos todas as chaves e seus valores
    while(i.hasNext()){
      Map.Entry entrada = (Map.Entry)i.next();
      System.out.println("Chave: " + entrada.getKey() +
        " - Valor: " + entrada.getValue());
    }

    System.exit(0);
  }
}

Chave: São Paulo - Valor: 49282768
Chave: Brasília - Valor: 96736887
Chave: Goiânia - Valor: 4334598

Resumo do código acima:
1º criação do objeto HashMap: new
2º inserção das chaves e de seus respectivos valores: put().
3º pegar os dados para visualização: entrySet()
4º inserir um iterator no conjunto de dados e proceder a visualização propriamente dita:
- set.iterator()
- while(i.hasNext()){
      Map.Entry entrada = (Map.Entry)i.next();
      System.out.println("Chave: " + entrada.getKey() +
        " - Valor: " + entrada.getValue());
    }


Uma observação importante em relação à classe HashMap é que esta não honra nenhuma ordem específica de seus elementos, ou seja, a ordem dos pares chave-valor em uma operação de exibição pode ser bem diferente da ordem de inserção.


Percorrendo dados em um mapa de dados

import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;
 
public class TestaInterfaceMap {
 
    public static void main(String[] args) {
    
        Map<Integer, String> mapaNomes = new HashMap<Integer, String>();
        mapaNomes.put(1, "João Delfino");
        mapaNomes.put(2, "Maria do Carmo");
        mapaNomes.put(3, "Claudinei Silva");
        
        //Collection<Integer> conjNomes = mapaNomes.keySet();
        
        Set<Entry<Integer, String>> set = mapaNomes.entrySet();
        Iterator it = set.iterator();
        
        System.out.println("Código\t\tValor");
        
//getKey() - recupera a chave do mapa
        //getValue() - recupera o valor do mapa
 
        while(it.hasNext()){
            Entry<Integer, String> entry = (Entry)it.next();
            System.out.println(entry.getKey() + "\t\t"+entry.getValue());
        }
    }
}

Execução:

Código        Valor
1        João Delfino
2        Maria do Carmo
3        Claudinei Silva


Também pode ser usado para percorrer um mapa o “for aprimorado”, mas vale informar que para percorrer os valores o seu valor começa por 1 e não por 0.

Percorrendo dados de um mapa com “for aprimorado”:

for(int i = 1; i <= mapaNomes.size(); i++){
    System.out.println(i + " - " + mapaNomes.get(i));
}

3.1. Ordenação de HashMap
Existe uma questão simples para fazer a ordenação de um mapa de dados. Para aplicar essa ordenação é necessário criar antes uma classe personalizada que implemente a interface Comparator do tipo inteiro e também trabalhar com a classe TreeSet.

3.1.1. Comparator personalizado

import java.util.Comparator;
import java.util.Map;
 
public class ComparatorInts implements Comparator<Integer> {
    
    Map<Integer, String> base;
    
    public ComparatorInts(Map<Integer, String> base) {
        this.base = base;
    }
    
    @Override
    public int compare(Integer o1, Integer o2) {
        return base.get(o1).compareTo(base.get(o2));
    }
}

3.1.2. Ordenação de um mapa por valor

Comparador personalizado:

import java.util.Comparator;
import java.util.Map;
 
public class ComparatorInts implements Comparator<Integer> {
    
    Map<Integer, String> base;
    
    public ComparatorInts(Map<Integer, String> base) {
        this.base = base;
    }
    
    @Override
    public int compare(Integer o1, Integer o2) {
        return base.get(o1).compareTo(base.get(o2));
    }
}


import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;
 
public class OrdenandoHashMap {
 
    public static void main(String[] args) {
        HashMap<Integer, String> mapaNomes = new HashMap<Integer, String>();
        mapaNomes.put(1, "João Delfino");
        mapaNomes.put(2, "Maria do Carmo");
        mapaNomes.put(3, "Claudinei Silva");
        mapaNomes.put(4, "Amélia Mourão");
        
        ComparatorInts compInt = new ComparatorInts(mapaNomes);
        
        Map<Integer, String> mapaOrdenado = new TreeMap(compInt);
        mapaOrdenado.putAll(mapaNomes);
        
        for(Integer valor : mapaOrdenado.keySet()){
            System.out.println(valor + " " + mapaNomes.get(valor));
        }
        
    }
}

Execução:

4 Amélia Mourão
3 Claudinei Silva
1 João Delfino
2 Maria do Carmo

Obs: A, C, J, M


Percorrer um HashMap e  verificar se a chave que eu estou percorrendo é diferente de null.
Se for, me retorna o conteúdo...se não, vai para a próxima chave!

import java.util.HashMap; 
import java.util.Set; 
 
public class Teste 

 
    public static void main(String[] args) 
    { 
        HashMap<String, String> mapa = new HashMap<String, String>(); 
        mapa.put("ch1", "Valor de ch1"); 
        mapa.put(null, "Teste"); 
        mapa.put(null, "Outro Teste"); 
        mapa.put("ch2", "Valor de ch2"); 
        Set<String> chaves = mapa.keySet(); 
        for (String chave : chaves) 
        { 
            if(chave != null) 
                System.out.println(chave +": "+ mapa.get(chave)); 
        } 
    }    
}

ch2: Valor de ch2
ch1: Valor de ch1

Outro exemplo simples que utiliza um HashMap é mostrado abaixo:

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

public class HashMapExample {

    public static void main(String[] args) {
        Map vehicles = new HashMap();

        // Add some vehicles.
        vehicles.put("BMW", 5);
        vehicles.put("Mercedes", 3);
        vehicles.put("Audi", 4);
        vehicles.put("Ford", 10);

        System.out.println("Total vehicles: " + vehicles.size());

        // Iterate over all vehicles, using the keySet method.
        for (Object key: vehicles.keySet()) {
            System.out.println(key + " - " + vehicles.get(key));
        }

        String searchKey = "Audi";
        if (vehicles.containsKey(searchKey))
            System.out.println("Found total " + vehicles.get(searchKey) + " "
                    + searchKey + " cars!\n");

        // Clear all values.
        vehicles.clear();

        // Equals to zero.
        System.out.println("After clear operation, size: " + vehicles.size());
    }
}

Execução:

Total vehicles: 4
Audi - 4
Ford - 10
BMW - 5
Mercedes - 3
Found total 4 Audi cars!

After clear operation, size: 0

Obs:
- A função Hash  é qualquer algoritmo que mapeie dados grandes e de tamanho variável para pequenos dados de tamanho fixo. Por esse motivo, as funções Hash são conhecidas por resumirem o dado. A principal aplicação dessas funções é a comparação de dados grandes ou secretos.
Dessa forma, as funções Hash são largamente utilizadas para buscar elementos em bases de dados, verificar a integridade de arquivos baixados ou armazenar e transmitir senhas de usuários. Neste artigo, o TechTudo explica tudo sobre as funções Hash, incluindo como funcionam, seus principais problemas e como são usadas em algumas aplicações.
- hash: s.1. Cook, prato feito de carne moída misturada com batata assada ou frita, 2. bagunça, confusão, 3. algo refeito ou reformado; v. 1. cortar em pequenos pedaços, 2. misturar, confundir, 3. rever, fazer uma revisão, to hash up an old story: reavivar uma velha história, to make a hash of: estragar, complicar.
- bucket (ˈbʌkɪt): s. 1.  balde (recipiente).


3.2. Qual é a diferença entre os seguintes mapas:

HashMap<String, Object> map = new HashMap<String, Object>();
Map<String, Object> map = new HashMap<String, Object>();

Não existe diferença entre os objectos. Há uma diferença na interface que tem para o objecto. No primeiro caso, a interface é HashMap<String, Object> , enquanto no segundo é Map<String, Object> . O objeto subjacente, porém, é o mesmo.

A vantagem de usar Map<String, Object> é que você pode alterar o objeto subjacente a ser um tipo diferente de mapa sem quebrar seu contrato com qualquer código que está usando. Se você declará-la como HashMap<String, Object> , você tem que mudar o seu contrato, se você quiser alterar a implementação subjacente.

Map é uma interface, não uma classe! O mapa é uma estrutura de dados que permite que você ligue cada valor a uma chave. Assim podemos acessar o valor pela chave.

A idéia de ser uma interface é poder trocar de implementação se muito impacto, facilitando a manutenção.

O HashMap, que na verdade herda de AbstractMap, que implementa a interface Map (é um padrão de projeto essa arquitetura, cujo nome não me lembro agora  ), é um tipo de Map, pois ele realiza a interface através do AbstractMap. A característica do HashMap é que ele não autoriza valores duplicados de chave, sendo que o último substitui o já adicionado.

4. Classe HashTable
Essa classe trabalha com algoritmo hash para conversão das chaves e um mecanismo de pesquisa de valores, sendo que tem seus métodos sincronizados (thread-safe) que permitem checar acessos concorrentes e armazenagem. Também possui uma eficiente pesquisa de elementos baseados em chave-valor, mas não aceita valores nulos.
A classe HashTable  implementa uma tabela hash e mapas chaves para valores. No entanto, nem a chave nem o valor pode ser nulo. Essa classe contém dois parâmetros fundamentais: capacidade inicial e desempenho, com as mesmas definições que o HashMap classe.

Sintaxe:
HashTable<E> mapa = new Type<E>();
E: é o objeto declarado, podendo ser classes Wrappers ou tipo de coleção.
Type: é o tipo de objeto da coleção a ser usado.

Exemplo de como pode ser desenvolvido um mapa com objeto "Cliente" usando HashTable:

import java.util.Hashtable;
 
public class TesteHashTable {
 
    public static void main(String[] args) {
        
        Cliente c1 = new Cliente("754.856.869-88","Valdinei Santos");
        Cliente c2 = new Cliente("828.929.222.12","Claire Moura");
        Cliente c3 = new Cliente("156.565.556-88","Vagner Seller");
        
        Hashtable<Integer, Cliente> ht = new Hashtable<Integer, Cliente>();
        ht.put(1, c1);
        ht.put(2, c2);
        ht.put(3, c3);
        
        System.out.println("CPF \t\t Cliente");
        for (int i = 1; i <= ht.size(); i++) {
            System.out.println(ht.get(i));
        }
    }
}
 
class Cliente{
    public String cpf;
    public String nome;
    
    public Cliente(String cpf, String nome) {
        this.cpf = cpf;
        this.nome = nome;  
    }
    
    @Override
    public String toString() {
        return cpf + " | " + nome;
    }
}

Execução:
CPF          Cliente
754.856.869-88 | Valdinei Santos
828.929.222.12 | Claire Moura
156.565.556-88 | Vagner Seller

Obs: a classe Cliente é uma classe interna a classe TesteHashTable, uma classe interna não pode ser pública.


Outro exemplo simples que utiliza um HashTable é mostrado abaixo:


import java.util.Hashtable;
import java.util.Map;

public class HashTableExample {

    public static void main(String[] args) {
        Map vehicles = new Hashtable();
       
        // Add some vehicles.
        vehicles.put("BMW", 5);
        vehicles.put("Mercedes", 3);
        vehicles.put("Audi", 4);
        vehicles.put("Ford", 10);
       
        System.out.println("Total vehicles: " + vehicles.size());
       
        // Iterate over all vehicles, using the keySet method.
        for(Object key: vehicles.keySet())
            System.out.println(key + " - " + vehicles.get(key));
        System.out.println();
       
        String searchKey = "Audi";
        if(vehicles.containsKey(searchKey))
            System.out.println("Found total " + vehicles.get(searchKey) + " "
                    + searchKey + "cars!\n");
       
        // Clear all values.
        vehicles.clear();
       
        // Equals to zero.
        System.out.println("After clear operation, size: " + vehicles.size());

        // The next statements throw a NullPointerException, if uncommented.
        //vehicles.put("Nissan", null);
        //vehicles.put(null, 6);
    }
}

Execução:
Total vehicles: 4
Mercedes - 3
BMW - 5
Ford - 10
Audi - 4

Found total 4 Audicars!

After clear operation, size: 0

4. TreeMap

O TreeMap é uma implementação Vermelho-Preto árvore que é classificada de acordo com a ordem natural das suas chaves, ou por um Comparator fornecido no momento da criação. Além disso, essa classe mantém uma ordem em seus elementos. Finalmente, esta classe não é sincronizada, assim, se um aplicativo usa vários segmentos, o mapa deve ser sincronizado externamente.

Um exemplo simples que utiliza um TreeMap é mostrado abaixo:

import java.util.TreeMap;

public class TreeMapExample {

    public static void main(String[] args) {
        TreeMap vehicles = new TreeMap();
       
        // Add some vehicles.
        vehicles.put("BMW", 5);
        vehicles.put("Mercedes", 3);
        vehicles.put("Audi", 4);
        vehicles.put("Ford", 10);
       
        System.out.println("Total vehicles: " + vehicles.size());
       
        // Iterate over all vehicles, using the keySet method.
        for(Object key: vehicles.keySet())
            System.out.println(key + " - " + vehicles.get(key));
        System.out.println();
       
        System.out.println("Highest key: " + vehicles.lastKey());
        System.out.println("Lowest key: " + vehicles.firstKey());
       
        System.out.println("\nPrinting all values:");
        for(Object val: vehicles.values())
            System.out.println(val);
        System.out.println();
       
        // Clear all values.
        vehicles.clear();
       
        // Equals to zero.
        System.out.println("After clear operation, size: " + vehicles.size());
    }
}

Execução:

Total vehicles: 4
Audi - 4
BMW - 5
Ford - 10
Mercedes - 3

Highest key: Mercedes
Lowest key: Audi

Printing all values:
4
5
10
3

After clear operation, size: 0


5. ConcurrentHashMap

A classe é uma tabela hash que suporta a simultaneidade. Assim, esta estrutura é seguro para uso em caso de vários segmentos. Finalmente, esta classe não permite nem chaves nem valores nulos.

Um exemplo simples que utiliza um ConcurrentHashMap é mostrado abaixo:

import java.util.Enumeration;
import java.util.concurrent.ConcurrentHashMap;

public class ConcurrentHashMapExample {
   
    public static void main(String[] args) {
        ConcurrentHashMap vehicles = new ConcurrentHashMap();
       
        // Add some vehicles.
        vehicles.put("BMW", 5);
        vehicles.put("Mercedes", 3);
        vehicles.put("Audi", 4);
        vehicles.put("Ford", 10);
       
        System.out.println("Total vehicles: " + vehicles.size());
       
        // Iterate over all vehicles, using the keySet method.
        for(Object key: vehicles.keySet())
            System.out.println(key + " - " + vehicles.get(key));
        System.out.println();
       
        String searchKey = "Audi";
        if(vehicles.containsKey(searchKey))
            System.out.println("Found total " + vehicles.get(searchKey) + " "
                    + searchKey + " cars!\n");
       
        Enumeration elems = vehicles.elements();
        while(elems.hasMoreElements())
            System.out.println(elems.nextElement());
        System.out.println();
       
        Object val = vehicles.putIfAbsent("Audi", 9);
        if(val != null)
            System.out.println("Audi was found in the map and its value was updated!");
       
        val = vehicles.putIfAbsent("Nissan", 9);
        if(val == null)
            System.out.println("Nissan wasn't found in map, thus a new pair was created!");
        System.out.println();
       
        // The next statements <span class="s614nmgjbwcz" id="s614nmgjbwcz_12">throw</span> a NullPointerException, if uncommented.
        //vehicles.put("Nissan", null);
        //vehicles.put(null, 6);
       
        // Clear all values.
        vehicles.clear();
       
        // Equals to zero.
        System.out.println("After clear operation, size: " + vehicles.size());
    }
}

Execução:

Total vehicles: 4
BMW - 5
Mercedes - 3
Audi - 4
Ford - 10

Found total 4 Audi cars!

5
3
4
10

Audi was found in the map and its value was updated!
Nissan wasn't found in map, thus a new pair was created!

After clear operation, size: 0

Obs: um cache é uma área de local de memória que armazena uma cópia dos dados acessados ​​com freqüência. Exemplos de tais dados incluem um resultado de uma consulta a um banco de dados, um arquivo em disco ou um relatório.

Exemplo Java que é Threadsafe usando HashMap sem usar sincronizados Coleções:

import java.util.*;

public class HashMapSynchronization {
    public static void main(String[] args) {
        // create map
        Map<String,String> map = new HashMap<String,String>();
       
        // populate the map
        map.put("1","ALIVE ");
        map.put("2","IS");
        map.put("3","AWESOME");
       
        // create a synchronized map
        Map<String,String> syncMap = Collections.synchronizedMap(map);
       
        System.out.println("Synchronized map :"+syncMap);
    }
}

Execução:
Synchronized map :{3=AWESOME, 2=IS, 1=ALIVE }