Java/이론

자바 - Comparable, Comparator

sh1mj1 2023. 6. 1. 18:00

Comparable

이 인터페이스를 구현하는 각 클래스 개체에 순서를 지정합니다. 이 순서를 natural ordering(자연순서) 라고 하며 클래스의 compareTo 메서드를 자연 비교 메서드라고 합니다.

 

이 인터페이스를 구현하는 객체 List 나 Array 는 (이하 List) Collections.sort() 로 자동으로 정렬할 수 있습니다. 따로 comparator 을 지정하지 않아도 말이죠.

compareTo 메소드

public int compareTo(T o);

Comparable 은 compareTo 라는 메서드를 가지고 있습니다.

 

이 객체를 지정된 객체와 비교하여 순서를 지정하는 메소드입니다. 파라미터 o 는 nullable 입니다.

compareTo 메서드를 호출하는 객체가 파라미터인 o 객체보다 더 클 때 양수, 호출하는 객체가 더 작을 때 음수, 같을 때 0을 리턴합니다.

 

만약 e1.compareTo(e2) == 0e1.equals(e2) 이 같은 boolean 값을 같는다면 두 메서드는 동일합니다.

natural ordering 은 equals 와 같은 것이 좋습니다. 다르다면 sorted set(or map) 에서 이상하게 동작하기 때문입니다. Comparable 을 구현하는 모든 java core 클래스는 natural ordering 과 equals 가 같습니다. (java.math 는 예외임)

 

Comparable 을 구현하여 순서 지정

아래 코드로 순서를 지정하는 예를 들어봅시다.

class Student implements Comparable<Student>{
    String name;
    int age;

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public int compareTo(Student o) {
        if(this.age > o.age) return 1;
        else if (this.age < o.age) return  -1;
        return 0;
                // 이런 식으로도 사용할 수 있음.
                // return this.age - o.age;
    }
}
public class ComparableTest {
    public static void main(String[] args) {
        Student[] array = new Student[5];
        array[0] = new Student("AA", 22);
        array[1] = new Student("BB", 23);
        array[2] = new Student("CC", 19);
        array[3] = new Student("DD", 20);
        array[4] = new Student("EE", 23);

        Arrays.sort(array);
        for (Student st : array) {
            System.out.println("name: " + st.name + ", age: " +st.age);
        }
    }
}

 

Comparable 인터페이스를 구현한 후 compareTo() 메소드를 오버라이딩 해서 age 를 기준으로 오름차순 정렬하도록 한 코드입니다.

 

compareTo() 메서드의 코드 블록이 헷갈릴텐데

자바는 기본적으로 오름차순 정렬이며 compareTo() 메서드의 리턴값이 양수이면 오름차순, 음수이면 내림차순이라고 보면 됩니다.

 

———————— 출력 ————————
name: CC, age: 19
name: DD, age: 20
name: AA, age: 22
name: BB, age: 23
name: EE, age: 23

 

출력 결과를 보면 Student 기준으로 오름차순으로 잘 정렬이 된 것을 알 수 있습니다.

 

Comparator

일부 객체 컬렉션의 순서를 지정합니다. comparator 는 정렬 순서를 지정하여 sort method 로 전달될 수 있습니다.

순서가 없는 데이터 구조(sorted map/set) 의 순서를 지정하거나 제어할 수 있습니다.

 

sorted map/set 을 정렬하기 위해 equals 와 다른 순서를 지정할 때는 주의해야 합니다. Comparable 와 마찬가지로 이상하게 동작할 수 있기 때문입니다.

 

참고로 일반적으로 Comparator 는 java.io.Serializable 을 같이 구현하는 것이 좋습니다. TreeSet 이나 TreeMap 같은 Serializable 한 데이터 구조가 성공적으로 직렬화되기 위해서는 필요합니다.

 

Comparable 과 달리 선택적으로 null 인수의 비교를 허용할 수 있습니다.

 

이 인터페이스는 Comparable 인터페이스와 다르게 꽤 많은 메소드를 가지고 있습니다. 여기서 가장 중요한 compare 메소드를 사용하면 클래스 단위로 정렬 기준을 정의하는 Comparable 과 달리 객체마다의 정렬 기준을 정의할 수 있습니다.

 

compare 메소드

int compare(T o1, T o2);

 

두 argument 의 순서를 비교합니다. o1 이 o2 보다 더 작으면 음수, 같으면 0, 더 크면 양수를 리턴합니다.

 

Comparator 을 사용하여 순서를 지정하는 예

String[] strArray = {"Apple", "Banana", "Tangerine", "Pear", "Blueberry"};
Arrays.sort(strArray, new Comparator<String>() {
    @Override
    public int compare(String o1, String o2) {
        if (o1.length() > o2.length()) return -1;
        else if (o1.length() < o2.length()) return 1;
        return o1.compareTo(o2); // 문자열 길이가 같을 경우 알파벳 기준으로 오름차순 정렬.
    }
});
for (String str : strArray) {
    System.out.println(str);
}

sort 메소드의 두 번째 인자로 Comparator 익명 클래스를 구현해 넘겨주었습니다. Comparator 내부에 compare() 메소드를 오버라이딩 하여 정렬 기준을 작성했습니다.

 

그 결과 문자열의 길이가 긴 순서대로 정렬됩니다.

 

———————— 출력 ————————
Blueberry
Tangerine
Banana
Apple
Pear

 

Comparable 의 compareTo 보다 Comparator 의 compare 메소드가 더 헷갈리실텐데요. 아래와 같이 동작하는 것입니다.

o1 의 길이가 o2 보다 크면 -1(음수)을 리턴.

즉, o1 문자열의 길이가 더 크면 문자열의 길이 기준으로 내림차순으로 정렬한다는 것입니다.

 

compare 메소드를 람다 함수로 대체

위에 있는 코드 블록을 아래처럼 람다 함수로 바꿀 수 있습니다.

 

Arrays.sort(strArray, (o1, o2) -> {
    if (o1.length() > o2.length()) return -1;
    else if (o1.length() < o2.length()) return 1;
    return o1.compareTo(o2);
});

 

Comparator는 패러미터가 위처럼 두 개인 메소드가 하나 뿐이기 때문에 이렇게 표현할 수 있습니다.

그 밖에 Comparator 는 자바 8버전부터 여러 다른 메소드들을 갖고 있습니다. 크게 어려운 부분은 없으니 궁금할 때 찾아보면 될 것 같습니다.

 

 

아래 글을 참고하여 작성하였습니다.

https://www.guru99.com/comparable-vs-comparator-java.html

https://yuja-kong.tistory.com/entry/Java-객체-정렬-Comparable-Comparator

https://hongnewhonglog.tistory.com/31