본문

[Java] Comparable, Comparator 비교

반응형

 

이미지 출처: https://pediaa.com/

 

1. Comparable, Comparator는 왜 사용하는가?

int형 배열을 만들면 다음과 같이 Arrays.sort() 메서드를 사용하여 정렬을 할 수 있다.

int[] scores = {899, 982, 1090, 982, 1018};
Arrays.sort(scores);
System.out.println(Arrays.toString(scores)); // [899, 982, 982, 1018, 1090]

 

하지만 사용자가 임의로 정의한 객체는 기본형 데이터와 달리 정렬 기준이 없으면 정렬을 할 수 없다.

즉, 다음을 실행하면 컴파일 에러가 발생한다.

public class Player {
    private String name;
    private int score;

    public Player(String name, int score) {
        this.name = name;
        this.score = score;
    }

    // Getters, Setters 생략
}
List<Player> players = new ArrayList<>();
players.add(new Player("Alice", 899));
players.add(new Player("Bob", 982));
players.add(new Player("Chloe", 1090));
players.add(new Player("Dale", 982));
players.add(new Player("Eric", 1018));


// Compile error!
Collections.sort(players); 

 

2. Comparable

객체 간의 일반적인 정렬이 필요할 때, Comparable 인터페이스를 확장해서 정렬의 기준을 정의하는 compareTo() 메서드를 구현한다.

 

객체의 정렬 기준을 정의하는 첫번째 방법은

정렬 대상 클래스를 자바에서 기본적으로 제공하고 있는 Comparable 인터페이스를 구현하도록 변경하는 것이다.

이를 적용하면 Player 클래스는 다음과 같이 수정된다.

public class Player implements Comparable<Player> {
    // Fields, Getters, Setters 생략

    @Override
    public int compareTo(Player o) {
        return o.getScore() - getScore();
    }
}

 

Comparable 인터페이스의 compareTo() 메서드를 통해 인자로 넘어온 같은 타입의 다른 객체와 대소 비교가 가능

Collections.sort(players);

// [Player(name=Chloe, score=1090), Player(name=Eric, score=1018), Player(name=Bob, score=982), Player(name=Dale, score=982), Player(name=Alice, score=899)]
System.out.println(players); 

 

3. Comparator

정렬 가능한 클래스(Comparable 인터페이스를 구현한 클래스)들의 기본 정렬 기준과 다르게 정렬 하고 싶을 때 특정 기준을 정의하는 compare() 메서드를 구현한다. 

 

 

아래 코드는 Comparator 객체를 Collections.sort() 메서드의 두번째 인자로 넘겨서 이전 섹션과 동일한 정렬 결과 출력한다. Comparator 객체를를 인자로 넘기면, 정렬 대상 객체가 Comparable 인터페이스를 구현 여부와 상관없이, 넘어온 Comparator 구현체의 compare() 메서드 기준으로 정렬을 수행한다.

 

사용예시 1

a) 익명 클래스 사용방법

Comparator<Player> comparator = new Comparator<Player>() {
    @Override
    public int compare(Player a, Player b) {
        return b.getScore() - a.getScore();
    }
};

Collections.sort(players, comparator);

// [Player(name=Chloe, score=1090), Player(name=Eric, score=1018), Player(name=Bob, score=982), Player(name=Dale, score=982), Player(name=Alice, score=899)]
System.out.println(players); 

 

b) 람다 함수 사용방법

Collections.sort(players, (a, b) -> b.getScore() - a.getScore());

// [Player(name=Chloe, score=1090), Player(name=Eric, score=1018), Player(name=Bob, score=982), Player(name=Dale, score=982), Player(name=Alice, score=899)]
System.out.println(players);

 

 

사용예시 2

a) 익명 클래스 사용방법

public void comparatorExample1() {
    List<String> strings = new ArrayList<>();
    strings.add("This code is free software");
    strings.add("you can redistribute it");
    strings.add("under the terms of the GNU General Public License version 2 only");
    strings.add("This code is distributed in the hope that it will be useful");
    strings.add("Please contact Oracle");
    strings.add("500 Oracle Parkway, Redwood Shores, CA 94065 USA");

    // Sorting 하기 전에 출력
    for (String str : strings) {
        System.out.println(str);
    }

    // 문자 길이로 sorting (오름차순)
    Collections.sort(strings, new Comparator<String>() {
        @Override
        public int compare(String s1, String s2) {
            return s1.length() - s2.length();
        }
    });

    // sorting 후 출력
    System.out.println();
    for (String str : strings) {
        System.out.println(str);
    }
}

 

b) 람다 함수 사용방법

public void comparatorExample2() {
    List<String> strings = new ArrayList<>();
    strings.add("This code is free software");
    strings.add("you can redistribute it");
    strings.add("under the terms of the GNU General Public License version 2 only");
    strings.add("This code is distributed in the hope that it will be useful");
    strings.add("Please contact Oracle");
    strings.add("500 Oracle Parkway, Redwood Shores, CA 94065 USA");

    // Sorting 하기 전에 출력
    for (String str : strings) {
        System.out.println(str);
    }

    // 문자 길이로 sorting (오름차순)
    Collections.sort(strings, (s1, s2) -> s1.length() - s2.length());

    // sorting 후 출력
    System.out.println();
    for (String str : strings) {
        System.out.println(str);
    }
}

 

c) 결과

This code is free software
you can redistribute it
under the terms of the GNU General Public License version 2 only
This code is distributed in the hope that it will be useful
Please contact Oracle
500 Oracle Parkway, Redwood Shores, CA 94065 USA

Please contact Oracle
you can redistribute it
This code is free software
500 Oracle Parkway, Redwood Shores, CA 94065 USA
This code is distributed in the hope that it will be useful
under the terms of the GNU General Public License version 2 only

 

3. 정리

공통점은 정렬의 기준을 정의한다는 것이고, 차이점은 정렬 기준이 일반적이냐 일반적이지 않느냐와 compareTo(Object o) 메서드를 구현하느냐 compare(Object o1, Object o2) 메서드를 구현하느냐 라는 것이다.

 

반응형

공유

댓글