1. Обзор
В этом руководстве мы собираемся изучить различные способы сравнения двух HashMaps
в Java .
Мы обсудим несколько способов проверки сходства двух HashMaps
. Мы также будем использовать Java 8 Stream API и Guava, чтобы получить подробные различия между различными HashMaps
.
2. Использование Map.equals()
Во- первых, мы будем использовать Map.equals()
, чтобы проверить, имеют ли два HashMap
одинаковые записи:
@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));
}
Здесь мы создаем три объекта HashMap
и добавляем записи. Затем мы используем Map.equals()
, чтобы проверить, имеют ли два HashMap
одинаковые записи.
Работа Map.equals()
заключается в сравнении ключей и значений с помощью метода Object.equals()
.
Это означает, что он работает только тогда, когда и ключ, и объект-значение правильно реализуют equals() .
****
Например, Map.equals()
не работает, когда тип значения — массив, поскольку метод equals()
массива сравнивает идентификатор, а не содержимое массива:
@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. Использование API -интерфейса Java Stream
Мы также можем реализовать наш собственный метод для сравнения HashMaps
с помощью Java 8 Stream
API:
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())));
}
Для простоты мы реализовали метод areEqual()
, который теперь можно использовать для сравнения объектов HashMap<String, String>
:
@Test
public void whenCompareTwoHashMapsUsingStreamAPI_thenSuccess() {
assertTrue(areEqual(asiaCapital1, asiaCapital2));
assertFalse(areEqual(asiaCapital1, asiaCapital3));
}
Но мы также можем настроить наш собственный метод areEqualWithArrayValue()
для обработки значений массива, используя Arrays.equals()
для сравнения двух массивов:
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
Далее давайте посмотрим, как сравнить два ключа HashMap
и их соответствующие значения.
4.1. Сравнение ключей HashMap
Во- первых, мы можем проверить, имеют ли два HashMap
одинаковые ключи, просто сравнив их KeySet()
:
@Test
public void whenCompareTwoHashMapKeys_thenSuccess() {
assertTrue(asiaCapital1.keySet().equals(asiaCapital2.keySet()));
assertFalse(asiaCapital1.keySet().equals(asiaCapital3.keySet()));
}
4.2. Сравнение значений HashMap
Далее мы увидим, как сравнивать значения HashMap
одно за другим.
Мы реализуем простой метод проверки того, какие ключи имеют одинаковое значение в обоих HashMaps,
используя Stream
API:
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()
для сравнения двух разных 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. Сопоставьте разницу с использованием гуавы
Наконец, мы увидим, как получить подробную разницу между двумя HashMaps
с помощью Guava Maps.difference().
Этот метод возвращает объект MapDifference
, который имеет ряд полезных методов для анализа различий между картами.
Давайте посмотрим на некоторые из них.
5.1. MapDifference.entriesDiffering()
Во- первых, мы получим общие ключи, которые имеют разные значения в каждой HashMap
, используя MapDifference.entriesDiffering()
:
@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());
}
Метод entryDiffering()
возвращает новую карту
, содержащую набор общих ключей и объектов ValueDifference
в качестве набора значений.
Каждый объект ValueDifference
имеет методы leftValue()
и rightValue()
, которые возвращают значения в двух картах
соответственно.
5.2. MapDifference.entriesOnlyOnRight()
и MapDifference.entriesOnlyOnLeft()
Затем мы можем получить записи, которые существуют только в одном HashMap
, используя MapDifference.entriesOnlyOnRight()
и MapDifference.entriesOnlyOnLeft():
@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());
}
Но мы можем настроить метод, используемый для сравнения, с помощью Equivalence
.
Например, мы определим Equivalence
для типа String[]
для сравнения значений String[]
в наших HashMaps
по своему усмотрению :
@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. Заключение
В этой статье мы обсудили различные способы сравнения HashMaps
в Java. Мы узнали несколько способов проверить, равны ли два HashMaps
, а также как получить подробную разницу.
Полный исходный код доступен на GitHub .