Рубрики
Без рубрики

Сравнение массивов в Java

Посмотрите на различные способы сравнения массивов в Java.

Автор оригинала: baeldung.

1. Обзор

В этом уроке мы рассмотрим различные способы сравнения массивов в Java . Мы рассмотрим обычные методы, а также рассмотрим некоторые примеры использования лямбда выражений .

2. Сравнение Массивов

Мы собираемся сравнить массивы в Java, и, как мы знаем, это объекты. Поэтому давайте обновим некоторые основные понятия:

  • Объекты имеют ссылки и значения
  • Две равные ссылки должны указывать на одно и то же значение
  • Два разных значения должны иметь разные ссылки
  • Два равных значения не обязательно имеют одинаковые ссылки
  • Примитивные значения сравниваются только по значению
  • Строковые литералы сравниваются только по значению

2.1. Сравнение ссылок на объекты

Если у нас есть две ссылки, указывающие на один и тот же массив, мы всегда должны получать результат true в сравнении с оператором == .

Давайте рассмотрим пример:

String[] planes1 = new String[] { "A320", "B738", "A321", "A319", "B77W", "B737", "A333", "A332" };
String[] planes2 = planes1;

Во-первых, мы создали массив моделей плоскостей, на которые ссылается planes 1 . Затем мы создаем плоскости 2 , которые ссылаются на плоскости 1 . Делая это, мы создаем две ссылки | на один и тот же массив в памяти . Поэтому выражение “planes 1” вернет true .

Для массивов метод equals() совпадает с методом . Итак, planes 1.equals(planes 2) возвращает true , потому что обе ссылки ссылаются на один и тот же объект. Вообще говоря, array1.eqauls(array2) вернет true тогда и только тогда, когда выражение “|/array1” вернет true .

Давайте предположим, что эти две ссылки совпадают:

assertThat(planes1).isSameAs(planes2);

Давайте не будем уверены, что значения, на которые ссылается planes 1 , на самом деле совпадают со значениями, на которые ссылается planes 2 . Поэтому мы можем изменить массив, на который ссылается planes 2, , и проверить, оказывают ли изменения какое-либо влияние на массив, на который ссылается planes1 :

planes2[0] = "747";

Чтобы, наконец, увидеть, как это работает, давайте сделаем наши утверждения:

assertThat(planes1).isSameAs(planes2);
assertThat(planes2[0]).isEqualTo("747");
assertThat(planes1[0]).isEqualTo("747");

С помощью этого модульного теста мы смогли сравнить два массива по ссылке.

Однако мы только доказали, что одна ссылка, однажды присвоенная значению другой, будет ссылаться на то же значение.

Теперь мы создадим два разных массива с одинаковыми значениями:

String[] planes1 = new String[] { "A320", "B738", "A321", "A319", "B77W", "B737", "A333", "A332" };
String[] planes2 = new String[] { "A320", "B738", "A321", "A319", "B77W", "B737", "A333", "A332" };

Поскольку это разные объекты, мы точно знаем, что это не одно и то же. Поэтому мы можем сравнить их:

assertThat(planes1).isNotSameAs(planes2);

Подводя итог, в данном случае у нас есть два массива в памяти, которые содержат одни и те же значения String в точно таком же порядке. Однако не только массивы ссылок отличаются по содержанию, но и сами ссылки также отличаются.

2.2. Сравнение Длин Массивов

Длина массивов может сравниваться независимо от типов их элементов или от того, заполнены ли их значения .

Давайте создадим два массива:

final String[] planes1 = new String[] { "A320", "B738", "A321", "A319", "B77W", "B737", "A333", "A332" };
final Integer[] quantities = new Integer[] { 10, 12, 34, 45, 12, 43, 5, 2 };

Это два разных массива с разными типами элементов. В этом наборе данных мы регистрируем, например, сколько самолетов каждой модели хранится на складе. Теперь давайте запустим модульные тесты на них:

assertThat(planes1).hasSize(8);
assertThat(quantities).hasSize(8);

Таким образом, мы доказали, что оба массива содержат восемь элементов и что свойство length возвращает правильное количество элементов для каждого массива.

2.3. Сравнение массивов с массивами.

До сих пор мы сравнивали массивы только на основе их идентификаторов объектов. С другой стороны, чтобы проверить, равны ли два массива с точки зрения их содержимого, Java предоставляет статический метод Arrays.equals . Этот метод будет перебирать массивы по каждой позиции параллельно и применять, для каждой пары элементов .

Давайте создадим два разных массива с одинаковыми строковыми литералами в одном и том же порядке:

String[] planes1 = new String[] { "A320", "B738", "A321", "A319", "B77W", "B737", "A333", "A332" };
String[] planes2 = new String[] { "A320", "B738", "A321", "A319", "B77W", "B737", "A333", "A332" };

А теперь давайте утверждаем, что они равны:

assertThat(Arrays.equals(planes1, planes2)).isTrue();

Если мы изменим порядок значений второго массива:

String[] planes1 = new String[] { "A320", "B738", "A321", "A319", "B77W", "B737", "A333", "A332" };
String[] planes2 = new String[] { "B738", "A320", "A321", "A319", "B77W", "B737", "A333", "A332" };

Мы получим другой результат:

assertThat(Arrays.equals(planes1, planes2)).isFalse();

2.4. Сравнение массивов с массивами.deepEquals

Использование оператора == легко, если мы используем простые типы в Java . Это могут быть примитивные типы или String литералы. Сравнение массивов Object s может быть более сложным. Причина этого полностью объяснена в нашей статье Arrays.deepEquals . Давайте рассмотрим пример.

Во-первых, давайте начнем с класса Plane :

public class Plane {
    private final String name;
    private final String model;

    // getters and setters
}

И давайте реализуем методы hashCode и equals :

@Override
public boolean equals(Object o) {
    if (this == o)
        return true;
    if (o == null || getClass() != o.getClass())
        return false;
    Plane plane = (Plane) o;
    return Objects.equals(name, plane.name) && Objects.equals(model, plane.model);
}

@Override
public int hashCode() {
    return Objects.hash(name, model);
}

Во-вторых, давайте создадим следующие двухэлементные массивы:

Plane[][] planes1 
  = new Plane[][] { new Plane[]{new Plane("Plane 1", "A320")}, new Plane[]{new Plane("Plane 2", "B738") }};
Plane[][] planes2 
  = new Plane[][] { new Plane[]{new Plane("Plane 1", "A320")}, new Plane[]{new Plane("Plane 2", "B738") }};

Давайте теперь посмотрим, являются ли они истинными, глубоко равными массивами:

assertThat(Arrays.deepEquals(planes1, planes2)).isTrue();

Чтобы убедиться, что наше сравнение работает должным образом, давайте теперь изменим порядок нашего последнего массива:

Plane[][] planes1 
  = new Plane[][] { new Plane[]{new Plane("Plane 1", "A320")}, new Plane[]{new Plane("Plane 2", "B738") }};
Plane[][] planes2 
  = new Plane[][] { new Plane[]{new Plane("Plane 2", "B738")}, new Plane[]{new Plane("Plane 1", "A320") }};

Наконец, давайте проверим, действительно ли они больше не равны:

assertThat(Arrays.deepEquals(planes1, planes2)).isFalse();

2.5. Сравнение массивов с различными порядками элементов

Чтобы проверить, равны ли массивы, независимо от порядка элементов, нам нужно определить , что делает один экземпляр нашей Плоскости уникальным . В нашем случае достаточно другого имени или модели, чтобы определить, что одна плоскость отличается от другой. Мы установили это, уже реализовав оба метода hashCode и equals . Это означает, что прежде чем мы сможем сравнить наши массивы, мы должны их отсортировать. Для этого нам нужен Компаратор :

Comparator planeComparator = (o1, o2) -> {
    if (o1.getName().equals(o2.getName())) {
        return o2.getModel().compareTo(o1.getModel());
    }
    return o2.getName().compareTo(o1.getName());
};

В этом Компараторе мы отдаем приоритет имени. Если имена равны, мы решаем неоднозначность, глядя на модель. Мы сравниваем строки с помощью метода compareTo типа String .

Мы хотим иметь возможность определить, равны ли массивы независимо от порядка сортировки. Для этого давайте теперь отсортируем наши массивы:

Arrays.sort(planes1[0], planeComparator);
Arrays.sort(planes2[0], planeComparator);

И, наконец, давайте проверим их:

assertThat(Arrays.deepEquals(planes1, planes2)).isTrue();

Сначала отсортировав массивы в том же порядке, мы позволяем методу deepEquals найти, равны ли эти два массива.

3. Заключение

В этом уроке мы рассмотрели различные способы сравнения массивов. Во-вторых, мы увидели разницу между сравнением ссылок и значений. Кроме того, мы рассмотрели, как мы можем сравнивать массивы глубоко . Наконец, мы увидели разницу между обычным сравнением и глубоким сравнением с использованием equals и deepEquals соответственно.

Как всегда, полный исходный код примеров доступен на GitHub.