수정 비교 방법이 Java의 일반 계약 오류를 위반함

Mehvish Ashiq 2024년2월15일
  1. ComparatorComparable 인터페이스의 차이점
  2. ComparatorComparable에 대한 비교 규칙
  3. 비교 방법이 일반 계약을 위반함 오류가 있는 Java 코드
  4. ComparatorComparable 인터페이스를 사용하는 Java 솔루션
수정 비교 방법이 Java의 일반 계약 오류를 위반함

오늘은 ComparatorComparable 인터페이스에서 사용하는 비교 규칙에 대해 알아보겠습니다. 이로 인해 Java에서 comparison 메서드가 일반 계약을 위반함 오류가 발생할 수 있습니다. 그런 다음 ComparatorComparable 인터페이스를 사용하는 두 가지 솔루션을 이해합니다.

ComparatorComparable 인터페이스의 차이점

이들은 Java 핵심 라이브러리의 두 인터페이스입니다. 비교기는 서로 다른 두 개체를 비교하는 기능이며 다른 것과는 독립적입니다.

두 개의 입력만 찾고 프로세스를 계속 진행한 다음 결과를 표시합니다.

반면 Comparable은 데이터 클래스와 혼합되는 인터페이스입니다. 예를 들어, 일부 데이터가 있는 클래스가 있습니다. Comparable 인터페이스는 이 클래스의 첫 번째 개체를 같은 클래스의 두 번째 개체와 비교하는 데 사용됩니다.

이는 Comparable 인터페이스가 인스턴스를 동일한 클래스의 다른 인스턴스와 비교할 수 있음을 나타냅니다. Comparable은 클래스의 natural 순서를 정의합니다.

다른 측면에서는 Comparator와 같은 비교 함수이기도 하며 반환 값, 전이적, 재귀적 등에 대해 동일한 규칙을 가집니다.

ComparatorComparable에 대한 비교 규칙

비교 방법이 일반 계약을 위반함비교기 또는 비교 가능(우리가 사용하는 것에 따라)에 버그가 있고 일관성 규칙 중 하나를 위반함을 의미합니다. 일관성 규칙은 무엇입니까?

아래에서 배워봅시다.

정수 유형 값에 대한 Java 프로그램을 작성했다고 가정합니다. 따라서 비교 함수는 다음 규칙을 준수해야 합니다.

  • 임의의 두 정수 ab가 주어지면 삼분법이 충족되어야 합니다. 즉, 다음 관계 중 정확히 하나가 참이어야 합니다.

    • ab보다 작습니다(a < b인 경우 -ve 값 반환)
    • ab와 같습니다(a == b인 경우 0을 반환함)
    • ab보다 큽니다(a > b인 경우 +ve 값 반환)
  • 전이성을 만족해야 합니다. 즉, a < bb < c인 경우 세 숫자 a, b, c에 대해 a < c를 의미합니다.

  • 세 번째 규칙은 Antisymmetry에 관한 것입니다. 여기서 a < b~b < a를 의미합니다.

  • 대체 가능성은 a == ba < c라고 가정하는 비교 규칙이기도 합니다. 이것은 b < c를 의미합니다.

  • 최종 비교 규칙은 반사성입니다. 여기서 a == a입니다. 또한 ~a < a.

이러한 규칙 중 하나라도 위반되면 비교 방법이 일반 계약을 위반함이라는 오류가 발생합니다. 아래 코드 예제를 통해 배워봅시다.

비교 방법이 일반 계약을 위반함 오류가 있는 Java 코드

예제 코드:

// import libraries
import static java.util.stream.Collectors.toCollection;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Random;

// Main
public class Main {
  public static void main(String[] args) {
    // generate random numbers
    List<Integer> list = new Random(209).ints(32L).boxed().collect(toCollection(ArrayList::new));
    // sort using lambda expression
    list.sort(logging((a, b) -> a - b));
  } // end main()

  // logging the comparisons
  static Comparator<Integer> logging(Comparator<Integer> c) {
    return (a, b) -> {
      int r = c.compare(a, b);
      System.err.printf("%,14d %,14d => %,14d\n", a, b, r);
      return r;
    };
  } // end logging()
} // end class

이 코드에서는 난수 스트림을 생성하는 데 사용되는 Random 클래스의 ints 인스턴스를 사용하여 몇 가지 난수를 생성합니다.

이 코드의 경우 list.sort((a, b) -> a - b);로 정렬하면 그러면 문제가 무엇이며 어디에서 발생하는지 확인할 수 없습니다. 이것이 우리가 그것을 식별하는 데 도움이 될 로깅을 통해 정렬하는 이유입니다.

그것은 우리에게 오류를 주지만, 그것은 또한 많은 수의 비교를 제공합니다. 모두 다루지는 않겠지만 그 중 몇 가지는 오류를 찾기에 충분합니다.

출력:

수정 비교 방법이 java에서 일반 계약 오류를 위반함 - 오류

보시다시피 프로그램은 여기서 일관성 규칙을 위반하여 이 오류가 발생합니다. 다음 섹션에서는 ComparatorComparable을 사용하여 솔루션을 살펴보겠습니다.

ComparatorComparable 인터페이스를 사용하는 Java 솔루션

난수가 적은 Comparator 인터페이스를 사용해 봅시다.

예제 코드:

// import libraries
import static java.util.stream.Collectors.toCollection;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Random;

// Main
public class Main {
  public static void main(String[] args) {
    // generate random numbers
    List<Integer> list = new Random(5).ints(32L).boxed().collect(toCollection(ArrayList::new));
    // sort using lambda expression
    list.sort(logging((a, b) -> a - b));
  } // end main()

  // logging the comparisons
  static Comparator<Integer> logging(Comparator<Integer> c) {
    return (a, b) -> {
      int r = c.compare(a, b);
      System.err.printf("%,14d %,14d => %,14d\n", a, b, r);
      return r;
    };
  } // end logging()
} // end class

이 코드는 성공적으로 실행됩니다. 우리는 모든 비교를 거치지는 않지만 확인을 위해 몇 가지 비교를 볼 것입니다.

다음 스크린샷을 확인하십시오.

출력:

수정 비교 메서드는 java에서 일반 계약 오류를 위반함 - 솔루션 1

비교를 위한 Comparable 인터페이스를 사용하여 오류가 없는 Java 코드에 대해 알아봅시다. 이 인터페이스를 사용하려면 데이터를 포함하는 클래스를 만들어야 합니다.

아래에서 해봅시다.

예제 코드(Students.java 클래스):

public class Student implements Comparable<Student> {
  private String firstName;
  private String lastName;

  public Student(String firstName, String lastName) {
    this.firstName = firstName;
    this.lastName = lastName;
  }

  public String getFirstName() {
    return firstName;
  }

  public void setFirstName(String firstName) {
    this.firstName = firstName;
  }

  public String getLastName() {
    return lastName;
  }

  public void setLastName(String lastName) {
    this.lastName = lastName;
  }

  public int compareTo(Student other) {
    /*
    compare the last names and save the result
    in `compareResult` variable
    */
    int compareResult = this.lastName.compareTo(other.lastName);

    /*
    If both last names match, then it would be true means 0. So,
    dive into the `if` condition and check if the count of their
    first name matches.
    if this.count == other.count return 0
    if this.count > other.count return 1
    if this.count < other.count return -1
    */

    if (compareResult == 0) {
      if (this.firstName.chars().count() == other.firstName.chars().count()) {
        compareResult = 0;
        return compareResult;
      } else if (this.firstName.chars().count() > other.firstName.chars().count()) {
        compareResult = 1;
        return compareResult;
      } else {
        compareResult = -1;
        return compareResult;
      }
    } else {
      return compareResult;
    }
  }
}

예제 코드(Main.java 클래스):

public class Main {
  public static void main(String[] args) {
    Student std1 = new Student("Mehvish", "Ashiq");
    Student std2 = new Student("Mehvish", "Ashiq");
    System.out.println("Result of Comparison 1: " + std1.compareTo(std2));

    Student std3 = new Student("Aftab", "Ashiq");
    Student std4 = new Student("Mehvish", "Ashiq");
    System.out.println("Result of Comparison 2: " + std3.compareTo(std4));

    Student std5 = new Student("Mehr-un-nissa", "Ashiq");
    Student std6 = new Student("Mehvish", "Ashiq");
    System.out.println("Result of Comparison 3: " + std5.compareTo(std6));
  }
}

출력:

Result of Comparison 1: 0
Result of Comparison 2: -1
Result of Comparison 3: 1

이 코드에서는 두 개체의 lastName이 동일한 경우 firstName의 문자 수를 비교합니다.

보시다시피 결과는 일관됩니다. a==b, a<ba>b인 경우 각각 0, -11을 반환합니다.

Mehvish Ashiq avatar Mehvish Ashiq avatar

Mehvish Ashiq is a former Java Programmer and a Data Science enthusiast who leverages her expertise to help others to learn and grow by creating interesting, useful, and reader-friendly content in Computer Programming, Data Science, and Technology.

LinkedIn GitHub Facebook

관련 문장 - Java Error