자바에서 비교기 및 비교 가능

1. 소개

Java에서의 비교는 매우 쉽습니다. 그렇지 않을 때까지.

사용자 지정 형식으로 작업하거나 직접 비교할 수없는 개체를 비교하려는 경우 비교 전략을 사용해야합니다. 간단하게 만들 수 있지만 Comparator 또는 Comparable 인터페이스를 사용합니다.

2. 예제 설정

랭킹에 따라 선수를 정렬하려는 축구 팀의 예를 들어 보겠습니다.

간단한 Player 클래스 를 만드는 것으로 시작하겠습니다 .

public class Player { private int ranking; private String name; private int age; // constructor, getters, setters }

다음으로 PlayerSorter 클래스를 만들어 컬렉션을 만들고 Collections.sort를 사용하여 정렬 해 보겠습니다 .

public static void main(String[] args) { List footballTeam = new ArrayList(); Player player1 = new Player(59, "John", 20); Player player2 = new Player(67, "Roger", 22); Player player3 = new Player(45, "Steven", 24); footballTeam.add(player1); footballTeam.add(player2); footballTeam.add(player3); System.out.println("Before Sorting : " + footballTeam); Collections.sort(footballTeam); System.out.println("After Sorting : " + footballTeam); } 

예상대로 이로 인해 컴파일 타임 오류가 발생합니다.

The method sort(List) in the type Collections is not applicable for the arguments (ArrayList)

여기서 우리가 뭘 잘못했는지 이해합시다.

3. 비교 가능

이름에서 알 수 있듯이 Comparable 은 객체를 동일한 유형의 다른 객체와 비교하는 전략을 정의하는 인터페이스입니다. 이를 클래스의 "자연 순서"라고합니다.

따라서 정렬 할 수 있으려면 Comparable 인터페이스 를 구현하여 플레이어 개체를 비교할 수 있도록 정의해야합니다 .

public class Player implements Comparable { // same as before @Override public int compareTo(Player otherPlayer) { return Integer.compare(getRanking(), otherPlayer.getRanking()); } } 

정렬 순서는 compareTo () 메서드 의 반환 값에 의해 결정됩니다 . Integer.compare (X, Y) -1을 리턴하는 경우 , X가 11보다 Y , 그렇지 않으면 0을 반환있는 거 같은지 복귀 한 경우.

이 메서드는 비교할 개체가 인수로 전달되는 개체보다 작은 지, 같은지 또는 큰지를 나타내는 숫자를 반환합니다.

마지막으로 PlayerSorter를 실행하면 플레이어 가 순위별로 정렬 된 것을 볼 수 있습니다 .

Before Sorting : [John, Roger, Steven] After Sorting : [Steven, John, Roger]

이제 Comparable을 사용 하여 자연스러운 순서를 명확하게 이해 했으므로 인터페이스를 직접 구현하는 것보다 더 유연한 방식으로 다른 유형의 순서를 사용하는 방법을 살펴 보겠습니다 .

4. 비교기

비교기 인터페이스는 정의 비교 (ARG1, ARG2) 방법 개체를 비교하고 비슷한 역할을 나타내는 두 개의 인수 Comparable.compareTo () 메소드를.

4.1. 비교기 생성

Comparator 를 생성하려면 Comparator 인터페이스 를 구현해야합니다 .

첫 번째 예에서는 Player순위 속성 을 사용하여 플레이어 를 정렬 하는 Comparator 를 만들 것입니다 .

public class PlayerRankingComparator implements Comparator { @Override public int compare(Player firstPlayer, Player secondPlayer) { return Integer.compare(firstPlayer.getRanking(), secondPlayer.getRanking()); } }

마찬가지로 플레이어연령 속성 을 사용하여 플레이어 를 정렬 하는 비교기 를 만들 수 있습니다 .

public class PlayerAgeComparator implements Comparator { @Override public int compare(Player firstPlayer, Player secondPlayer) { return Integer.compare(firstPlayer.getAge(), secondPlayer.getAge()); } }

4.2. 비교기 액션

개념을 설명하기 위해 실제로 사용하려는 Comparator 의 인스턴스 인 Collections.sort 메서드에 두 번째 인수를 도입하여 PlayerSorter 를 수정하겠습니다 .

이 접근 방식을 사용하여 자연 순서를 재정의 할 수 있습니다 .

PlayerRankingComparator playerComparator = new PlayerRankingComparator(); Collections.sort(footballTeam, playerComparator); 

이제 PlayerRankingSorter를 실행 하여 결과 확인 하겠습니다 .

Before Sorting : [John, Roger, Steven] After Sorting by ranking : [Steven, John, Roger]

다른 정렬 순서를 원할 경우 사용중인 비교기 만 변경하면 됩니다.

PlayerAgeComparator playerComparator = new PlayerAgeComparator(); Collections.sort(footballTeam, playerComparator);

이제 PlayerAgeSorter를 실행하면 연령별 로 다른 정렬 순서를 볼 수 있습니다 .

Before Sorting : [John, Roger, Steven] After Sorting by age : [Roger, John, Steven]

4.3. 자바 8 비교기

Java 8은 람다 식과 compare () 정적 팩토리 메서드 를 사용하여 비교기 를 정의하는 새로운 방법을 제공합니다 .

람다 식을 사용하여 Comparator 를 만드는 방법에 대한 간단한 예를 살펴 보겠습니다 .

Comparator byRanking = (Player player1, Player player2) -> Integer.compare(player1.getRanking(), player2.getRanking());

Comparator.comparing 방법은 아이템을 비교하기 위해 사용되는 속성을 계산하는 방법을 취하고, 매칭 반환 비교기 인스턴스 :

Comparator byRanking = Comparator .comparing(Player::getRanking); Comparator byAge = Comparator .comparing(Player::getAge);

Java 8 Comparator.comparing 가이드에서 Java 8 기능을 자세히 살펴볼 수 있습니다.

5. 비교기비교 가능

대등 인터페이스는 기본 순서를 정의하기 위해 사용하는 경우 좋은 선택입니다 그것은 개체를 비교하는 주요 방법 인 경우에, 즉, 또는.

그런 다음 Comparable이 이미있는 경우 왜 Comparator를 사용하는지 자문 해보아야합니다 .

몇 가지 이유가 있습니다.

  • 때로는 객체를 정렬하려는 클래스의 소스 코드를 수정할 수 없어 Comparable 사용이 불가능합니다.
  • 사용 비교기를 우리가 허용하는 것은 우리의 도메인 클래스에 추가 코드를 추가 피하기 위해
  • Comparable을 사용할 때 불가능한 여러 다른 비교 전략을 정의 할 수 있습니다.

6. 빼기 속임수 피하기

이 튜토리얼을 진행하는 동안 Integer.compare () 메서드를 사용하여 두 정수를 비교했습니다. 이 영리한 한 줄을 대신 사용해야한다고 주장 할 수도 있습니다.

Comparator comparator = (p1, p2) -> p1.getRanking() - p2.getRanking();

다른 솔루션에 비해 훨씬 간결하지만 Java에서 정수 오버플로의 피해자가 될 수 있습니다 .

Player player1 = new Player(59, "John", Integer.MAX_VALUE); Player player2 = new Player(67, "Roger", -1); List players = Arrays.asList(player1, player2); players.sort(comparator);

Since -1 is much less than the Integer.MAX_VALUE, “Roger” should come before the “John” in the sorted collection. However, due to integer overflow, the “Integer.MAX_VALUE – (-1)” will be less than zero. So, based on the Comparator/Comparable contract, the Integer.MAX_VALUE is less than -1, which is obviously incorrect.

Hence, despite what we expected, “John” comes before the “Roger” in the sorted collection:

assertEquals("John", players.get(0).getName()); assertEquals("Roger", players.get(1).getName());

7. Conclusion

In this tutorial, we explored the Comparable and Comparator interfaces and discussed the differences between them.

To understand more advanced topics of sorting, check out our other articles such as Java 8 Comparator, Java 8 Comparison with Lambdas.

그리고 평소처럼 소스 코드는 GitHub에서 찾을 수 있습니다.