JavaでのHashMapのコピー

1. 概要

このチュートリアルでは、_https://www.baeldung.com/java-hashmap [HashMap ] _およびJavaで_HashMap_をコピーするためのいくつかのテクニック。
また、特定の場合に役立つ外部ライブラリのいくつかを検討します。

2. 浅いvsディープコピー

まず、_HashMaps_の浅いコピーと深いコピーの概念を理解しましょう。

2.1. 浅いコピー

  • _HashMap_の浅いコピーは、元の_HashMap_と同じキーおよび値オブジェクトへのマッピングを持つ新しい_HashMap_です。*

    たとえば、_Employee_クラスを作成してから、_Employee_インスタンスを値として持つマップを作成します。
public class Employee {
    private String name;

    // constructor, getters and setters
}
HashMap<String, Employee> map = new HashMap<>();
Employee emp1 = new Employee("John");
Employee emp2 = new Employee("Norman");
map.put("emp1", emp1);
map.put("emp2", emp2);
次に、元のマップとその浅いコピーが異なるオブジェクトであることを確認します。
HashMap<String, Employee> shallowCopy = // shallow copy implementation
assertThat(shallowCopy).isNotSameAs(map);
これはシャローコピーであるため、_Employee_インスタンスのプロパティを変更すると、元のマップとそのシャローコピーの両方に影響します。
emp1.setFirstName("Johny");
assertThat(shallowCopy.get("emp1")).isEqualTo(map.get("emp1"));

2.2. ディープコピー

  • _HashMap_のディープコピーは、すべてのマッピングを深くコピーする新しい_HashMap_です。したがって、すべてのキー、値、およびマッピングに対して新しいオブジェクトを作成します。

    ここで、マッピング(キー値)を明示的に変更しても、ディープコピーには影響しません。
HashMap<String, Employee> deepCopy = // deep copy implementation

emp1.setFirstName("Johny");

assertThat(deepCopy.get("emp1")).isNotEqualTo(map.get("emp1"));

3. HashMap API

3.1. HashMap C onstructorを使用する

_HashMap_â€〜s parameterized constructor _HashMap(Map <? Kを拡張しますか? V> m)_を拡張します* *マップ全体を浅くコピーする簡単な方法を提供します:*
HashMap<String, Employee> shallowCopy = new HashMap<String, Employee>(originalMap);

3.2. _Map.clone()_の使用

コンストラクターと同様に、_HashMap _#_ clone_メソッドも簡単な浅いコピーを作成します。
HashMap<String, Employee> shallowCopy = originalMap.clone();

3.3. _Map.put()_を使用する

_HashMap_は、各エントリを繰り返し処理し、別のマップで_put()_メソッドを呼び出すことにより、簡単に簡単にコピーできます。
HashMap<String, Employee> shallowCopy = new HashMap<String, Employee>();
Set<Entry<String, Employee>> entries = originalMap.entrySet();
for (Map.Entry<String, Employee> mapEntry : entries) {
    shallowCopy.put(mapEntry.getKey(), mapEntry.getValue());
}

3.4. _Map.putAll()_の使用

すべてのエントリを反復処理する代わりに、_putAll()_メソッドを使用して、すべてのマッピングを1ステップで浅くコピーできます。
HashMap<String, Employee> shallowCopy = new HashMap<>();
shallowCopy.putAll(originalMap);
一致するキーが存在する場合、* _ put()_および_putAll()_が値を置き換えることに注意してください。
また、_HashMap_âsのコンストラクタ、_clone()_、および_putAll()_の実装を見ると、すべてのエントリが同じ内部メソッドを使用してエントリをコピーしていることがわかります– _putMapEntries( )_。

4. Java 8 Stream APIを使用した_ * HashMap * _のコピー

link:/java-8-streams[Java 8 _Stream_ API]を使用して、_HashMap_の浅いコピーを作成できます。
Set<Entry<String, Employee>> entries = originalMap.entrySet();
HashMap<String, Employee> shallowCopy = (HashMap<String, Employee>) entries.stream()
  .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));

5. Google Guava

link:/guava-maps[Guava Maps]を使用すると、ソート済みのbiマップとともに、不変のマップを簡単に作成できます。 これらのマップの不変の浅いコピーを作成するには、_copyOf_メソッドを使用できます。
Map<String, Employee> map = ImmutableMap.<String, Employee>builder()
  .put("emp1",emp1)
  .put("emp2",emp2)
  .build();
Map<String, Employee> shallowCopy = ImmutableMap.copyOf(map);

assertThat(shallowCopy).isSameAs(map);

6. アパッチコモンズラング

*現在、Javaにはディープコピーの実装が組み込まれていません。
Apache Commonsには、_clone()_メソッドを使用してディープコピーを作成する_SerializationUtils_があります。 このため、ディープコピーに含まれるクラスは、_Serializable_インターフェイスを実装する必要があります。
public class Employee implements Serializable {
    // implementation details
}

HashMap<String, Employee> deepCopy = SerializationUtils.clone(originalMap);

7. 結論

このクイックチュートリアルでは、_HashMap__sの浅いコピーと深いコピーの概念とともに、Javaで_HashMap_をコピーするさまざまな手法を見てきました。
また、浅いコピーと深いコピーを作成するのに非常に便利な外部ライブラリのいくつかを調査しました。
これらの実装の完全なソースコードと単体テストは、https://github.com/eugenp/tutorials/tree/master/java-collections-maps-2 [GitHub]プロジェクトで入手できます。