Javaで2つのHashMapを比較する
1概要
このチュートリアルでは、2つの
HashMaps
をJavaで比較するためのさまざまな方法を探ります。
2つの
HashMaps
が似ているかどうかを確認する方法は複数あります。
Java 8 Stream APIとGuavaを使用して、さまざまな
HashMaps
の詳細な違いを把握します。
2
Map.equals()
を使用する
まず、
Map.equals()
を使用して、2つの
HashMaps
に同じエントリがあるかどうかを確認します。
@Test
public void whenCompareTwoHashMapsUsingEquals__thenSuccess() {
Map<String, String> asiaCapital1 = new HashMap<String, String>();
asiaCapital1.put("Japan", "Tokyo");
asiaCapital1.put("South Korea", "Seoul");
Map<String, String> asiaCapital2 = new HashMap<String, String>();
asiaCapital2.put("South Korea", "Seoul");
asiaCapital2.put("Japan", "Tokyo");
Map<String, String> asiaCapital3 = new HashMap<String, String>();
asiaCapital3.put("Japan", "Tokyo");
asiaCapital3.put("China", "Beijing");
assertTrue(asiaCapital1.equals(asiaCapital2));
assertFalse(asiaCapital1.equals(asiaCapital3));
}
ここでは、3つの
HashMap
オブジェクトを作成し、エントリを追加しています。次に、
Map.equals()
を使用して、2つの
HashMaps
に同じエントリがあるかどうかを確認します。
-
Map.equals()
の機能は、
__
Object.equals()
** メソッドを使用してキーと値を比較することです。 equals()__を正しく実装してください。
たとえば、
Map.equals()
は、配列の
equals()
メソッドが配列の内容ではなくidentityを比較するため、値の型がarrayの場合は機能しません。
@Test
public void whenCompareTwoHashMapsWithArrayValuesUsingEquals__thenFail() {
Map<String, String[]> asiaCity1 = new HashMap<String, String[]>();
asiaCity1.put("Japan", new String[]{ "Tokyo", "Osaka" });
asiaCity1.put("South Korea", new String[]{ "Seoul", "Busan" });
Map<String, String[]> asiaCity2 = new HashMap<String, String[]>();
asiaCity2.put("South Korea", new String[]{ "Seoul", "Busan" });
asiaCity2.put("Japan", new String[]{ "Tokyo", "Osaka" });
assertFalse(asiaCity1.equals(asiaCity2));
}
3 Java
Stream
API
を使用する
-
Java 8
Stream
APIを使って
HashMaps
を比較する独自のメソッドを実装することもできます。
private boolean areEqual(Map<String, String> first, Map<String, String> second) {
if (first.size() != second.size()) {
return false;
}
return first.entrySet().stream()
.allMatch(e -> e.getValue().equals(second.get(e.getKey())));
}
簡単にするために、
HashMap <String、String>
オブジェクトの比較に使用できる
areEqual()
メソッドを実装しました。
@Test
public void whenCompareTwoHashMapsUsingStreamAPI__thenSuccess() {
assertTrue(areEqual(asiaCapital1, asiaCapital2));
assertFalse(areEqual(asiaCapital1, asiaCapital3));
}
ただし、2つの配列を比較するために
Arrays.equals()
を使用して、配列値を処理するための独自のメソッド
areEqualWithArrayValue()
をカスタマイズすることもできます。
private boolean areEqualWithArrayValue(Map<String, String[]> first, Map<String, String[]> second) {
if (first.size() != second.size()) {
return false;
}
return first.entrySet().stream()
.allMatch(e -> Arrays.equals(e.getValue(), second.get(e.getKey())));
}
Map.equals()
とは異なり、独自のメソッドは
HashMaps
と配列値を比較します。
@Test
public void whenCompareTwoHashMapsWithArrayValuesUsingStreamAPI__thenSuccess() {
assertTrue(areEqualWithArrayValue(asiaCity1, asiaCity2));
assertFalse(areEqualWithArrayValue(asiaCity1, asiaCity3));
}
4
HashMap
キーと値の比較
次に、2つの
HashMap
キーとそれに対応する値を比較する方法を見てみましょう。
4.1. ハッシュマップキーの比較
まず、
KeySet()
を比較するだけで、2つの
HashMaps
に同じキーがあるかどうかを確認できます。
@Test
public void whenCompareTwoHashMapKeys__thenSuccess() {
assertTrue(asiaCapital1.keySet().equals(asiaCapital2.keySet()));
assertFalse(asiaCapital1.keySet().equals(asiaCapital3.keySet()));
}
4.2.
HashMap
値の比較
次に、
HashMap
値を1つずつ比較する方法を説明します。
Stream
APIを使用して、両方の
HashMaps
でどのキーが同じ値を持つかをチェックする簡単な方法を実装します。
private Map<String, Boolean> areEqualKeyValues(Map<String, String> first, Map<String, String> second) {
return first.entrySet().stream()
.collect(Collectors.toMap(e -> e.getKey(),
e -> e.getValue().equals(second.get(e.getKey()))));
}
areEqualKeyValues()
を使用して、2つの異なる
HashMaps
を比較して、どのキーが同じ値を持ち、どれが異なる値を持つかを詳細に確認できます。
@Test
public void whenCompareTwoHashMapKeyValuesUsingStreamAPI__thenSuccess() {
Map<String, String> asiaCapital3 = new HashMap<String, String>();
asiaCapital3.put("Japan", "Tokyo");
asiaCapital3.put("South Korea", "Seoul");
asiaCapital3.put("China", "Beijing");
Map<String, String> asiaCapital4 = new HashMap<String, String>();
asiaCapital4.put("South Korea", "Seoul");
asiaCapital4.put("Japan", "Osaka");
asiaCapital4.put("China", "Beijing");
Map<String, Boolean> result = areEqualKeyValues(asiaCapital3, asiaCapital4);
assertEquals(3, result.size());
assertThat(result, hasEntry("Japan", false));
assertThat(result, hasEntry("South Korea", true));
assertThat(result, hasEntry("China", true));
}
5 Guava
を使用したマップの違い
最後に、Guava
Maps.difference()を使用して、2つの
HashMaps__の詳細な違いを取得する方法を説明します。
このメソッドは、違いを分析するための便利なメソッドを多数含むhttps://google.github.io/guava/releases/20.0/api/docs/com/google/common/collect/MapDifference.html[
MapDifference
]オブジェクトを返します。これらのいくつかを見てみましょう。
5.1.
MapDifference.entriesDiffering()
まず、
MapDifference.entriesDiffering()
** を使用して、各
HashMap
に異なる値を持つ共通キーを取得します。
@Test
public void givenDifferentMaps__whenGetDiffUsingGuava__thenSuccess() {
Map<String, String> asia1 = new HashMap<String, String>();
asia1.put("Japan", "Tokyo");
asia1.put("South Korea", "Seoul");
asia1.put("India", "New Delhi");
Map<String, String> asia2 = new HashMap<String, String>();
asia2.put("Japan", "Tokyo");
asia2.put("China", "Beijing");
asia2.put("India", "Delhi");
MapDifference<String, String> diff = Maps.difference(asia1, asia2);
Map<String, ValueDifference<String>> entriesDiffering = diff.entriesDiffering();
assertFalse(diff.areEqual());
assertEquals(1, entriesDiffering.size());
assertThat(entriesDiffering, hasKey("India"));
assertEquals("New Delhi", entriesDiffering.get("India").leftValue());
assertEquals("Delhi", entriesDiffering.get("India").rightValue());
}
entriesDiffering()
メソッドは、共通キーのセットと
ValueDifference
オブジェクトを値のセットとして含む新しい
Map
を返します。
-
各
ValueDifference
オブジェクトには、それぞれ2つの
Maps
** の値を返す
leftValue()
メソッドと
rightValue()
メソッドがあります。
5.2.
MapDifference.entriesOnlyOnRight()
および
MapDifference.entriesOnlyOnLeft()
次に、
MapDifference.entriesOnlyOnRight()
と
MapDifference.entriesOnlyOnLeft()を使用して、1つの
HashMap__にのみ存在するエントリを取得できます。
@Test
public void givenDifferentMaps__whenGetEntriesOnOneSideUsingGuava__thenSuccess() {
MapDifference<String, String> diff = Maps.difference(asia1, asia2);
Map<String, String> entriesOnlyOnRight = diff.entriesOnlyOnRight();
Map<String, String> entriesOnlyOnLeft = diff.entriesOnlyOnLeft();
assertEquals(1, entriesOnlyOnRight.size());
assertEquals(1, entriesOnlyOnLeft.size());
assertThat(entriesOnlyOnRight, hasEntry("China", "Beijing"));
assertThat(entriesOnlyOnLeft, hasEntry("South Korea", "Seoul"));
}
5.3.
MapDifference.entriesInCommon()
次に、__MapDifference.entriesInCommon()を使用して一般的なエントリを取得します。
@Test
public void givenDifferentMaps__whenGetCommonEntriesUsingGuava__thenSuccess() {
MapDifference<String, String> diff = Maps.difference(asia1, asia2);
Map<String, String> entriesInCommon = diff.entriesInCommon();
assertEquals(1, entriesInCommon.size());
assertThat(entriesInCommon, hasEntry("Japan", "Tokyo"));
}
5.4.
Maps.difference()
動作のカスタマイズ
Maps.difference()
はデフォルトでエントリを比較するために
equals()
と
hashCode()
を使用するので、それらを正しく実装していないオブジェクトに対してはうまくいきません。
@Test
public void givenSimilarMapsWithArrayValue__whenCompareUsingGuava__thenFail() {
MapDifference<String, String[]> diff = Maps.difference(asiaCity1, asiaCity2);
assertFalse(diff.areEqual());
}
しかし、
同等性
を使用して、比較に使用する方法をカスタマイズできます。
たとえば、
HashMaps
の
String[]
値を比較するために、
String[]
型に____Equivalenceを定義します。
@Test
public void givenSimilarMapsWithArrayValue__whenCompareUsingGuavaEquivalence__thenSuccess() {
Equivalence<String[]> eq = new Equivalence<String[]>() {
@Override
protected boolean doEquivalent(String[]a, String[]b) {
return Arrays.equals(a, b);
}
@Override
protected int doHash(String[]value) {
return value.hashCode();
}
};
MapDifference<String, String[]> diff = Maps.difference(asiaCity1, asiaCity2, eq);
assertTrue(diff.areEqual());
diff = Maps.difference(asiaCity1, asiaCity3, eq);
assertFalse(diff.areEqual());
}
6. 結論
この記事では、Javaで
HashMaps
を比較するさまざまな方法について説明しました。 2つの
HashMaps
が等しいかどうかを確認する方法と、詳細な違いを確認する方法を複数学習しました。
完全なソースコードはhttps://github.com/eugenp/tutorials/tree/master/java-collections-maps[GitHubで利用可能]です。