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

1. Общ преглед

В този урок ще разгледаме различни начини за сравняване на масиви в Java . Ще разгледаме конвенционалните методи и ще видим и някои примери, използващи ламбда изрази .

2. Сравняване на масиви

Ще сравним масивите в Java и както знаем, това са обекти. Затова нека освежим някои основни понятия:

  • Обектите имат препратки и стойности
  • Две равни препратки трябва да сочат към една и съща стойност
  • Две различни стойности трябва да имат различни препратки
  • Две равни стойности не са задължително да имат еднакви препратки
  • Примитивните стойности се сравняват само по стойност
  • Stral литералите се сравняват само по стойност

2.1. Сравняване на препратки към обекти

Ако имаме две препратки, сочещи към един и същ масив, винаги трябва да получаваме резултат true в равно сравнение с оператора == .

Нека разгледаме един пример:

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

Първо, създадохме масив от равнинни модели, посочени от planes1 . След това създаваме равнини2 , които препращат равнини1 . Правейки това, ние създаваме две препратки към един и същ масив в паметта . Следователно изразът „planes1 == planes2“ ще върне true .

За масивите методът equals () е същият като оператора == . И така, planes1.equals (planes2) връща true, тъй като и двете препратки се отнасят към един и същ обект. Най-общо казано, array1.eqauls (array2) ще върне true, ако и само ако изразът array1 == array2 ″ връща true .

Нека твърдим дали двете препратки са еднакви:

assertThat(planes1).isSameAs(planes2);

Нека сега бъдем сигурни, че стойностите, посочени от равнини1 , всъщност са същите като тези, посочени от равнини2 . Следователно можем да променим масива, посочен от planes2, и да проверим дали промените оказват влияние върху масива, посочен от 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. Сравняване на масиви с Arrays.equals

Досега сравнявахме само масиви въз основа на техните идентичности на обекти. От друга страна, за да провери дали два масива са равни по отношение на тяхното съдържание, Java предоставя статичния метод Arrays.equals . Този метод ще извърши итерация през масивите паралелно на всяка позиция и ще приложи оператора == за всяка двойка елементи .

Нека създадем два различни масива с еднакви String литерали в абсолютно същия ред:

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. Сравняване на масиви с Arrays.deepEquals

Използването на оператора == е лесно, ако използваме прости типове в Java . Това могат да бъдат примитивни типове или Stral литерали. Сравнението между масивите на Object s може да бъде по-сложно. Причината за това е напълно обяснена в нашата статия за Arrays.deepEquals . Да видим пример.

Първо, нека започнем с клас самолет :

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  @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()); };

In this Comparator, we're giving priority to the name. If the names are equal, we solve the ambiguity by looking at the model. We compare strings by using the compareTo method of type String.

We want to be able to find if arrays are equal regardless of the sorting order. To do that, let's now sort our arrays:

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

And finally, let's test them:

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

Having sorted the arrays in the same order first, we allow the deepEquals method to find if these two arrays are equal.

3. Conclusion

В този урок видяхме различни начини за сравняване на масиви. Второ, видяхме разликата между сравняването на препратки и стойности. Освен това разгледахме как можем да сравним дълбоко масивите . И накрая, видяхме разликата между нормално сравнение и дълбоко сравнение, използвайки съответно equals и deepEquals .

Както винаги, пълният изходен код за примерите е достъпен в GitHub.