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で利用可能]です。