Comparable과 Comparator로 컬렉션 정렬
Comparable과 Comparator 모두 컬렉션을 정렬하는데 필요한 메서드를 정의하고 있는 인터페이스이다.
기본 정렬 기준을 구현하는데 사용.
Comparable을 구현하는 클래스들: 같은 타입의 인스턴스끼리 서로 비교할 수 있는 클래스들(wrapper, String, Date, File 클래스 등). ⇒ 정렬이 가능함을 의미.
기본적으로 오름차순으로 정렬되도록 구현되어 있음.
java.lang
패키지 소속.
멤버로 오직 compareTo()만 가짐.
public interface Comparable<T> {
public int compareTo(T o); // 객체 자신(this)과 o를 비교
}
compareTo()의 반환값은 int이지만 실제로는 비교하는 두 객체가 같으면 0, 비교하는 값보다 작으면 음수, 크면 양수를 반환하도록 구현해야 함.
예)
public final class Integer extends Number implements Comparable<Integer> {
...
public int compareTo(Integer anotherInteger) {
return compare(this.value, anotherInteger.value);
}
public static int compare(int x, int y) {
return (x < y) ? -1 : ((x == y) ? 0 : 1);
}
...
}
기본 정렬 기준 외에 다른 기준으로 정렬하고자 할 때 사용.
java.util
패키지 소속.
public interface Comparator<T> {
int compare(T o1, T o2); // o1과 o2를 비교
boolean equals(Object obj);
...
}
compareTo()와 마찬가지로 객체를 비교해서 음수, 0, 양수 중의 하나를 반환하도록 구현.
equals()는 오버라이딩 할 수 있지만 구현하지 않아도 무방.
예)
public class Arrays {
...
static final class NaturalOrder implements Comparator<Object> {
public int compare(Object first, Object second) {
return ((Comparable<Object>)first).compareTo(second);
}
...
}
...
}
Arrays.sort()는 배열 정렬을 위한 메서드이다. Comparator를 지정해주지 않으면 저장하는 객체(Comparable을 구현한 클래스의 객체)에 구현된 내용에 따라 정렬된다.
String의 Comparable 구현은 문자열이 사전 순(오름차순)으로 정렬되도록 작성되어 있다(공백 → 숫자 → 대문자 → 소문자와 같이 문자의 유니코드 순서가 작은 값부터 큰 값으로 정렬).
public static void main(String[] args) {
String[] arr = {"cake", "banana", "oreo", "apple", "app1e", "0re0"};
Arrays.sort(arr); // [0re0, app1e, apple, banana, cake, oreo]
}
만약 문자열의 내림차순으로 정렬하고 싶다면 다음과 같이 Comparator를 구현하면 된다.
public static void main(String[] args) {
String[] arr = {"cake", "banana", "oreo", "apple", "app1e", "0re0"};
Arrays.sort(arr, new Comparator() {
@Override
public int compare(Object o1, Object o2) {
if (o1 instanceof String && o2 instanceof String)
return ((String) o2).compareTo((String) o1);
return 0;
}
}); // [oreo, cake, banana, apple, app1e, 0re0]
}
만약 사용자가 정의한 객체를 정렬하려면 어떻게 해야할까? 앞서 언급한 것처럼 비교할 수 있는 객체는 Comparable을 구현해야 한다. 따라서 사용자 정의 객체에 Comparable을 구현하고 compareTo()를 오버라이딩 하면 된다. 아래 예제는 메뉴 가격이 적은 순서대로 정렬되도록 구현하였다.
public class Menu implements Comparable<Menu> {
private String menuName;
private int price;
public Menu(String menuName) {
this.menuName = menuName;
}
public Menu(String menuName, int price) {
this.menuName = menuName;
this.price = price;
}
public String getMenuName() {
return menuName;
}
public int getPrice() {
return price;
}
@Override
public String toString() {
return "<" + menuName + ": " + price + ">";
}
@Override
public int compareTo(Menu menu) {
return this.getPrice() - menu.getPrice();
}
}
public static void main(String[] args) {
Menu[] menus = {
new Menu("coffee", 3500),
new Menu("tea", 3000),
new Menu("ade", 4500),
};
System.out.println(Arrays.toString(menus));
// 실행 결과
// [<coffee: 3500>, <tea: 3000>, <ade: 4500>]
Arrays.sort(menus);
System.out.println(Arrays.toString(menus));
// 실행 결과
// [<tea: 3000>, <coffee: 3500>, <ade: 4500>]
}