티스토리 뷰

CS/Java

Comparator와 Comparable

bool-flower 2022. 5. 29. 21:41

Comparator와 Comparable는 자바로 알고리즘 문제를 풀다 보면 반드시 접하게 된다. 나도 최근 알고리즘 공부를 진행하면서 이 인터페이스들을 구현할 필요가 있었고, 아직 완전히 숙지하지 못한 것 같아 정리해본다.

정렬


어떤 문제에서는 임의로 클래스를 생성해서 객체 간의 값을 비교할 수 있도록 정렬 기준을 정의할 필요가 있다. 이때 사용하는 것이 이 글의 주제인 Comparator 인터페이스와 Comparable 인터페이스이다. 보통 자바에서는 아래 코드로 배열 또는 리스트를 정렬한다.

Arrays.sort(arr);
Collections.sort(list);

자바에서 정렬은 특별한 정의가 되어 있지 않으면 오름차순을 기준으로 한다. 

 

Comparable


Comparable 인터페이스는 compareTo라는 메서드를 선언하고 있다. 이름대로 객체 간의 비교를 위한 메서드인데, 파라미터 하나만을 전달받는다. 구현체는 이 메서드를 구현함으로써 정렬 기준을 정의한다.

public interface Comparable<T> {
    public int compareTo(T o);
}

Comparable 인터페이스를 구현한 객체, 자신과 파라미터로 들어오는 객체 o와 비교한 뒤 int 값을 반환한다.

그 예시로, 아래 코드를 보면

class Score implements Comparable<Score> {

    String name;
    int math;

    @Override
    public int compareTo(Score other) {
        return this.math - other.math;
    }
}

Score 라는 클래스를 통해 Comparable 인터페이스를 구현하고 있다. 그런데 Score 클래스의 멤버는 String 타입의 name과 int 타입의 math 두 가지가 있는데, 둘 중에 무엇을 기준으로 비교해야 할까?
compareTo 메서드 내부를 보면 this.math에 파라미터로 전달되는 other.math를 빼고 있다. 즉, name 값과는 상관없이 math 값 만으로 this 객체와 other 객체 간의 비교를 수행하는 것이다. 원하면 name 값도 비교하도록 메서드를 구현할 수도 있겠다.

아무튼, 위 코드상으로는 this.math가 other.math보다 크다면 양수, 작다면 음수를 반환하게 된다. 여기서 반환되는 수의 부호는 위치를 바꾸느냐 아니냐를 정한다. compareTo가 음수를 반환할 경우 두 원소의 위치를 바꾸지 않는다. 반대로 양수를 반환할 경우 두 원소의 위치를 바꾼다. 음수를 반환하려면, this.math가 other.math보다 작아야 한다. 반대로 양수를 반환하려면 this.math가 더 커야 한다. 앞서 정렬은 기본적으로 오름차순으로 수행된다고 했다. this 객체의 값이 더 작으면서, 음수를 반환하면 오름차순으로 정렬된다고 기억하면 될 것 같다.

반대로 내림차순으로 정렬하고 싶다면, 부호를 반대로 바꾸기만 하면 된다. 아래 코드를 참고하자.

public int compareTo(Score other) {
    return  other.math - this.math;
}

 

Comparator


Comparator 인터페이스는 compare 라는 메서드를 선언하고 있다. compare 외에도 다른 메서드들을 선언하고 있지만 이 글에서는 다루지 않는다. Comparable 인터페이스와는 파라미터가 두 개인 것 외에 큰 차이는 없다. 

public interface Comparator<T> {
    int compare(T o1, T o2);
}

인터페이스 내부에는 위와같이 선언되어있다.

class Score implements Comparator<Score> {

    String name;
    int math;

    @Override
    public int compare(Score o1, Score o2) {
        return o1.math - o2.math;
    }
}

compare 메서드도 음수를 반환할 경우 위치를 바꾸지 않고, 양수를 반환할 경우 위치를 바꾸게 된다. 

public int compare(Score o1, Score o2) {
	return o2.math - o1.math;
}

위와 같이 o1 와 o2의 위치를 바꾸면, 부호가 반대가 되어 역순으로 정렬 기준이 바뀐다.

 

Wrapper 클래스의 compare, compareTo 메서드


아래 코드는 국영수 점수에 따라 정렬 기준을 정하는 문제 풀이 일부이다. 

class Score implements Comparable<Score> {

    String name;
    int korean;
    int english;
    int math;

    @Override
    public int compareTo(Score other) {

        if (this.korean == other.korean && this.english == other.english && this.math == other.math) {
            return this.name.compareTo(other.name);
        }
        if (this.korean == other.korean && this.english == other.english) {
            return Integer.compare(other.math, this.math);
        }
        if (this.korean == other.korean) {
            return Integer.compare(this.english, other.english);
        }
        return Integer.compare(other.korean, this.korean);
    }
}

위 코드에서는 Integer 클래스는 compare 메서드를 사용하고 있다. 

Integer 클래스는 Comparable 인터페이스를 구현하지만, 내부에 compare 메서드도 구현되어 있다. 또한 compare 메서드를 호출함으로써 compareTo 메서드를 구현하고 있다.

Long, Double, Float처럼 수를 다루는 다른 래퍼 클래스도 같은 방식으로 동작한다. 

String 클래스의 비교를 조금 살펴보자. 문자열에서의 오름차순 정렬은 공백, 숫자, 대문자, 소문자 순으로 정렬하는 것을 의미한다. 정확히는, 문자의 유니코드 순서가 작은 값에서부터 큰 값으로 정렬되는 것이다. 아래는 String 클래스에 구현된 compareTo 메서드이다.

뿐만 아니라, 대소문자를 구분하지 않고 비교하는 Comparator를 상수 형태로 제공해준다. 구체적인 코드는 직접 살펴보기 바란당.

이펙티브 자바의 아이템 14를 보면 비교 수행 메서드를 구현할 때, if 문과 함께 '<' , '>' 같은 연산자를 쓰는 것보다 래퍼 클래스에 구현된 compare, compareTo 메서드를 통한 비교 값 반환을 권장한다. 

 

정리


이번 주제는 정렬을 하기 위해서는 반드시 알아야 하는 개념이다. Arrays 클래스Collections 클래스를 같이 공부하면 좀 더 쉽게 이해할 수 있을 것 같다.

Arrays와 Collections 클래스는 정렬을 수행할 때, Comparator를 지정해 주지 않으면 저장하는 객체(Comparable을 구현 클래스 객체)에 구현된 내용에 따라 정렬된다. 즉 해당 클래스의 기본 정렬 기준을 정하려면 Comparable 인터페이스를 구현하고, Comparable을 구현하지 않았거나 때에 따라 다른 기준으로 정렬하고 싶을 때는 Comparator를 구현하여 정렬 수행에 사용하면 된다. 

참조


https://st-lab.tistory.com/243

 

자바 [JAVA] - Comparable 과 Comparator의 이해

아마 이 글을 찾아 오신 분들 대개는 Comparable과 Comparator의 차이가 무엇인지 모르거나 궁금해서 찾아오셨을 것이다. 사실 알고보면 두 개는 그렇게 어렵지 않으나 아무래도 자바를 학습하면서 객

st-lab.tistory.com

https://mine-it-record.tistory.com/133

 

[JAVA] 자바_compareTo ( 값 [문자열/숫자] 비교 )

- 자바 compareTo - -마지막 수정날짜 : 2021-01-01- 과거 기록한 글이나 보기 힘든 부분도 있고 잘못 작성된 부분이 있어 내용 일부분 수정하였습니다. (잘못된 내용이 있는부분 적어주시면 바로바로

mine-it-record.tistory.com

 

'CS > Java' 카테고리의 다른 글

ArrayList에 요소가 추가되는 과정 파헤쳐보기  (0) 2023.02.03
Java Collection Framework  (0) 2022.11.16
equals  (0) 2022.10.05
System.out vs 로깅 라이브러리  (0) 2022.07.15
댓글
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday