1. 개요

이 사용방법(예제)에서는 Java에서 배열을 비교하는 다양한 방법을 살펴보겠습니다 . 우리는 기존의 방법을 다룰 것이고 람다 식을 사용하는 몇 가지 예도 볼 것 입니다.

2. 배열 비교

우리는 자바에서 배열을 비교할 것이고, 우리가 알다시피 이것들은 객체입니다. 따라서 몇 가지 기본 개념을 새로 고쳐 보겠습니다.

  • 객체에는 참조와 값이 있습니다.
  • 두 개의 동일한 참조가 동일한 값을 가리켜야 합니다.
  • 두 개의 서로 다른 값에는 서로 다른 참조가 있어야 합니다.
  • 두 개의 동일한 값이 반드시 동일한 참조를 가질 필요는 없습니다.
  • 기본 값은 값별로만 비교됩니다.
  • 문자열 리터럴은 값별로만 비교됩니다.

2.1. 객체 참조 비교

동일한 배열을 가리키는 두 개의 참조가 있는 경우 == 연산자를 사용한 등호 비교에서 항상 true  결과를 얻어야 합니다 .

예를 살펴보겠습니다.

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

먼저, planes1 에서 참조하는 평면 모델의 배열을 만들었습니다 . 그런 다음 planes1 을 참조하는 planes2 를 만듭니다 . 이렇게 하면 memory 에 동일한 배열에 대한 두 개의 참조 생성 됩니다 . 따라서  "planes1 == planes2"  표현식은 true 를 반환  합니다 .

배열의 경우  equals()  메서드는 == 연산자와 동일합니다 . 따라서 두 참조가 동일한 객체를 참조하고 있기 때문에 planes1.equals(planes2)  는 true를  반환  합니다. 일반적으로 말해서  array1.eqauls(array2)  는 " array1 == array2" 표현식이 true 를 반환하는  경우에만 true 를  반환  합니다 .

두 참조가 동일한지 확인합시다.

assertThat(planes1).isSameAs(planes2);

이제 planes1 에서 참조하는 값 이 실제로 planes2 에서 참조하는 값 과 동일한 지 확인 하겠습니다 . 따라서 우리는 planes2에서 참조하는 배열을 변경할 수 있으며 변경 사항이 plane1에서 참조하는 배열에 영향을 미치는지 확인할 수 있습니다 .

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);

요약하자면 이 경우 메모리에 동일한 문자열 값을 정확히 같은 순서로 포함하는 두 개의 배열이 있습니다 . 그러나 참조된 배열의 내용이 다를 뿐만 아니라 참조 자체도 다릅니다.

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);

이를 통해 두 배열에 8개의 요소가 있고 length 속성이 각 배열에 대해 올바른 수의 요소를 반환 한다는 것을 증명했습니다 .

2.3. Arrays.equals를 사용 하여 배열 비교

지금까지는 개체 ID를 기반으로 배열만 비교했습니다. 반면에  두 배열의 내용이 동일한지 확인하기 위해 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. Arrays.deepEquals 와 배열 비교

Java에서 단순 유형을 사용하는 경우 == 연산자를 사용하는 것은 쉽습니다 . 이들은 기본 유형 또는 문자열  리터럴일 수 있습니다  . Object 배열 간의 비교는 더 복잡할 수 있습니다. 그 이유는 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);
}

둘째, 다음과 같은 2요소 배열을 생성해 보겠습니다.

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. 요소 순서가 다른 배열 비교

배열이 동일한지 확인하려면 요소의 순서에 관계없이 Plane의인스턴스를 고유 하게 만드는 요소를 정의해야 합니다 . 우리의 경우 다른 이름이나 모델로 한 평면이 다른 평면과 다르다고 판단하기에 충분합니다. 우리는 이미 hashCode 와  equals  메소드를 모두 구현함으로써 이것을 확립했습니다 . 이것은 배열을 비교하기 전에 배열을 정렬해야 함을 의미합니다. 이를 위해 Comparator 가 필요합니다 .

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

Comparator 에서는 이름에 우선 순위를 둡니다. 이름이 같으면 모델을 보고 모호성을 해결합니다. String 유형 compareTo  메소드를  사용하여 문자열을 비교 합니다.

정렬 순서에 관계없이 배열이 동일한지 찾을 수 있기를 원합니다. 이를 위해 이제 배열을 정렬해 보겠습니다.

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

마지막으로 테스트해 보겠습니다.

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

먼저 같은 순서로 배열을 정렬한 후 deepEquals 메서드가 이 두 배열이 같은지 찾을 수 있도록 합니다 .

3. 결론

이 예제에서는 배열을 비교하는 다양한 방법을 보았습니다. 둘째, 참조와 값을 비교하는 것의 차이점을 보았습니다. 또한 배열을 깊이 비교하는 방법을 살펴보았습니다 . 마지막으로 equals  와  deepEquals 를 사용하는 일반 비교와 심층 비교의 차이점을 확인했습니다  .

항상 그렇듯이 예제의 전체 소스 코드는 GitHub에서 사용할 수  있습니다.

Junit footer banner