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 를 사용하는 일반 비교와 심층 비교의 차이점을 확인했습니다 .