Explain Codes LogoExplain Codes Logo

Copying a HashMap in Java

java
deep-copy
shallow-copy
clone
Alex KataevbyAlex Kataev·Feb 3, 2025
TLDR

For a quick and dirty shallow copy of a HashMap, you tap into the powers of the clone() method:

// Release the clone! (Star Wars fans, anyone?) HashMap<Integer, String> copiedMap = (HashMap<Integer, String>) originalMap.clone();

However, if you yearn for the uniqueness of a deep copy, where each entry is a fresh new instance, you summon the help of a loop or a powerful library to serialize and deserialize your objects:

// The world isn't enough. Let's get a new, cloned one! HashMap<Integer, String> deepCopiedMap = originalMap.entrySet() .stream() .collect(Collectors.toMap(Map.Entry::getKey, e -> new String(e.getValue()), (oldValue, newValue) -> oldValue, HashMap::new));

In other words, when you're in a hurry, use clone(). But if you want a copy so deep that changes in the copy won't meddle with the original, serialization is your secret weapon.

Digging into Shallow Copies

Constructor-based Copying

To make a shallow copy of a HashMap, you could simply hand over the original map to the welcoming arms of a new HashMap's constructor:

// Out with the old, in with the...equally old? HashMap<Integer, String> shallowCopy = new HashMap<>(originalMap);

This breeds a new HashMap sporting the same bindings as the original, but beware - these are mere references to the same objects.

The putAll() Modus Operandi

Alternatively, you could create a pristine HashMap and infuse it with the essence of the original using putAll():

// Empty shell seeking meaningful data relationships. Enjoys long walks on the beach. HashMap<Integer, String> anotherShallowCopy = new HashMap<>(); anotherShallowCopy.putAll(originalMap);

This tactic is a bit more espionage-like but manages to create an equally effective shallow copy.

Deep Copy - The Descent

The Immutable Saga

Immutable objects like String just need a shallow copy - they refuse to change, making them dependable comrades. But mutable objects are free spirits, needing a deep copy for full containment.

Practical Deep Copy

When making copies of maps featuring these mutable individuals, you can enlist the help of the Map.copyOf() method (Java 10+) armed with a custom value mapper:

// Custom cloning: because uniqueness isn't overrated. HashMap<Integer, CustomObject> deepCopy = (HashMap<Integer, CustomObject>) Map.copyOf( originalMap.entrySet().stream() .collect(Collectors.toMap( Map.Entry::getKey, e -> e.getValue().clone() // Clone wars! (only for Cloneable-enabled CustomObject, mind you) )) );

This strategy serves you with an immutable map in return. If you need the freedom to modify the map, you summon Collectors.toMap() with a re-mapping function.

Serialization Perks

Serialization, or the transformation from object to byte stream and back, is a workaround for cloning those Serializable ("please clone me") objects:

// Born as a Map; reborn as a byte stream; resurrected as a Map again. Thug life! ByteArrayOutputStream byteOut = new ByteArrayOutputStream(); ObjectOutputStream out = new ObjectOutputStream(byteOut); out.writeObject(originalMap); ByteArrayInputStream byteIn = new ByteArrayInputStream(byteOut.toByteArray()); ObjectInputStream in = new ObjectInputStream(byteIn); HashMap<Integer, CustomObject> serializedCopy = (HashMap<Integer, CustomObject>) in.readObject();

Recall, this approach is like that extra-tasty latte - more delicious but also more resource-intensive.

The Secrets of Data Elasticity

Key-property Immutability

It's good etiquette (and code sense) to hold keys to your HashMap as immutable to maintain integrity, especially when you're going for a shallow copy.

Clone Handling of Arrays

Should your HashMap house arrays or complex objects among its ranks, remember to enlist System.arraycopy() or dedicated cloning methods for utmost efficiency.

Deep Cloning of Classes

For intricate objects, consider embedding a deepClone() method in those classes to ensure accurate reproduction of internal states.

Trouble in Paradise - Challenges

Beware Mutable Fields

Mutable fields copied shallowly can be ticking time bombs - changes in one map could precipitate changes in the other, breeding pesky bugs, which are the bane of peaceful coding.

Handling Shared Object References

A shallow copy means shared references to the same objects. So, saying "change is good" in the copy could result in an unwelcome "echo" in the original.

Threading Hazards

Updating a HashMap in a multithreaded chaos could cause race conditions, leading to unexpected outcomes or even total havoc.

Tools for Complex Scenarios

External libraries, like our trusted old friend Apache Commons Lang, come with utilities such as serialization helpers that make deep copying less of a rollercoaster ride. And let's not forget the tutorials that often act as stepping stones to better understanding.