Copiando um HashMap em Java
1. Visão geral
2. Cópias superficiais vs profundas
Em primeiro lugar, vamos entender o conceito de cópias superficiais e profundas emHashMaps.
2.1. Cópia rasa
Uma cópia superficial deHashMap é um novoHashMap com mapeamentos para a mesma chave e objetos de valor que oHashMap original.
Por exemplo, vamos criar uma classeEmployee e, em seguida, um mapa com instânciasEmployee como valores:
public class Employee {
private String name;
// constructor, getters and setters
}
HashMap map = new HashMap<>();
Employee emp1 = new Employee("John");
Employee emp2 = new Employee("Norman");
map.put("emp1", emp1);
map.put("emp2", emp2);
Agora, vamos verificar se o mapa original e sua cópia superficial são objetos diferentes:
HashMap shallowCopy = // shallow copy implementation
assertThat(shallowCopy).isNotSameAs(map);
Como esta é uma cópia superficial, se alterarmos as propriedades de uma instânciaEmployee, isso afetará o mapa original e sua cópia superficial:
emp1.setFirstName("Johny");
assertThat(shallowCopy.get("emp1")).isEqualTo(map.get("emp1"));
2.2. Cópia profunda
A deep copy of a HashMap is a new HashMap that deeply copies all the mappings. Portanto, ele cria novos objetos para todas as chaves, valores e mapeamentos.
Aqui, a modificação explícita dos mapeamentos (valores-chave) não afetará a cópia detalhada:
HashMap deepCopy = // deep copy implementation
emp1.setFirstName("Johny");
assertThat(deepCopy.get("emp1")).isNotEqualTo(map.get("emp1"));
3. APIHashMap
3.1. Usando o sonstrutorHashMapC
construtor parametrizado deHashMapHashMap(Map<? extends K,? extends V> m)provides a quick way to shallow copy an entire map:
HashMap shallowCopy = new HashMap(originalMap);
3.2. UsandoMap.clone()
Semelhante ao construtor, o métodoHashMap #clone também cria uma cópia superficial rápida:
HashMap shallowCopy = originalMap.clone();
3.3. UsandoMap.put()
UmHashMap pode ser facilmente copiado superficialmente iterando sobre cada entrada e chamando o métodoput() em outro mapa:
HashMap shallowCopy = new HashMap();
Set> entries = originalMap.entrySet();
for (Map.Entry mapEntry : entries) {
shallowCopy.put(mapEntry.getKey(), mapEntry.getValue());
}
3.4. UsandoMap.putAll()
Em vez de iterar por todas as entradas, podemos usar o métodoputAll(), que copia superficialmente todos os mapeamentos em uma etapa:
HashMap shallowCopy = new HashMap<>();
shallowCopy.putAll(originalMap);
Devemos observar queput() and putAll() replace the values if there is a matching key.
Também é interessante notar que, se olharmos para o construtor deHashMap,clone() e a implementação deputAll(), descobriremos que todos eles usam o mesmo método interno para copiar entradas -putMapEntries().
4. CopiandoHashMap usando a API Java 8Stream
Podemos usarJava 8 Stream API para criar uma cópia superficial de umHashMap:
Set> entries = originalMap.entrySet();
HashMap shallowCopy = (HashMap) entries.stream()
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
5. Google Guava
UsandoGuava Maps,, podemos criar facilmente mapas imutáveis, junto com o mapa classificado e bi. Para fazer uma cópia imutável e superficial de qualquer um desses mapas, podemos usar o métodocopyOf:
Map map = ImmutableMap.builder()
.put("emp1",emp1)
.put("emp2",emp2)
.build();
Map shallowCopy = ImmutableMap.copyOf(map);
assertThat(shallowCopy).isSameAs(map);
6. Apache Commons Lang
Now, Java doesn’t have any built-in deep copy implementations. Portanto, para fazer uma cópia profunda, podemos substituir o métodoclone() ou usar uma técnica de serialização-desserialização.
O Apache Commons temSerializationUtils com um métodoclone() para criar uma cópia profunda. Para isso, qualquer classe a ser incluída na cópia profunda deve implementar a interfaceSerializable:
public class Employee implements Serializable {
// implementation details
}
HashMap deepCopy = SerializationUtils.clone(originalMap);
7. Conclusão
Neste tutorial rápido, vimos várias técnicas para copiar umHashMap em Java, junto com o conceito de cópia superficial e profunda paraHashMaps.
Além disso, exploramos algumas das bibliotecas externas que são bastante úteis para criar cópias superficiais e profundas.
O código-fonte completo dessas implementações junto com os testes de unidade estão disponíveis no projetoGitHub.