비교
Comparable, Comparator
왜 사용하는가?
- 객체를 정렬하거나 대소 비교할 때, 기본 타입과 달리 객체는
>, < 연산자를 사용할 수 없음
- 정렬 기준을 명시적으로 정의하기 위해 사용
TreeSet, TreeMap, Arrays.sort(), Collections.sort() 등이 내부적으로 비교 인터페이스를 활용
특이점
- 구현하지 않고 비교 시도 →
ClassCastException 발생
TreeSet, TreeMap은 반드시 비교 기준이 있어야 동작
Comparable
[비교 가능한]이라는 뜻
- 객체 자신이 가지는 기본 정렬 기준(natural ordering)을 정의
- "이 타입은 이렇게 정렬되는 것이 기본이다"를 명시
compareTo(T o) 메서드 구현
반환값 규칙
| 반환값 |
의미 |
| 음수 |
this가 o보다 작음 |
| 0 |
같음 |
| 양수 |
this가 o보다 큼 |
class Member implements Comparable<Member> {
String name;
int age;
@Override
public int compareTo(Member o) {
return this.name.compareTo(o.name); // 이름 기준 오름차순
// return this.age - o.age; // 나이 기준 오름차순
}
}
Comparator
[비교자]라는 뜻
- 객체 외부에서 정의하는 정렬 전략
- 상황·화면·정책에 따라 정렬 기준을 유연하게 변경 가능
compare(T o1, T o2) 메서드 구현
class AgeComparator implements Comparator<Member> {
@Override
public int compare(Member o1, Member o2) {
return Integer.compare(o1.getAge(), o2.getAge()); // 나이 오름차순
}
}
// 람다로 간결하게
Comparator<Member> byAge = (o1, o2) -> Integer.compare(o1.getAge(), o2.getAge());
Comparator<Member> byName = Comparator.comparing(Member::getName);
Comparator<Member> byAgeDesc = Comparator.comparingInt(Member::getAge).reversed();
Comparable vs Comparator
| 항목 |
Comparable |
Comparator |
| 위치 |
객체 내부 |
객체 외부 |
| 메서드 |
compareTo(T o) |
compare(T o1, T o2) |
| 정렬 기준 |
기본 정렬 1가지 |
다양한 정렬 전략 |
| 변경 |
코드 수정 필요 |
전략 교체만으로 변경 가능 |
Tree 구조에서의 사용
TreeSet, TreeMap은 요소 삽입 시 정렬 기준이 반드시 필요
Comparable 구현 객체: 자동으로 기본 정렬
Comparator 전달: 정렬 기준을 직접 지정
어떻게 사용하는가?
Member member1 = new Member("A", 10);
Member member2 = new Member("B", 20);
Member[] members = {member2, member1};
// Comparable 기반 정렬 (기본 정렬)
Arrays.sort(members);
// Comparator 기반 정렬 (나이 기준)
Arrays.sort(members, new AgeComparator());
Arrays.sort(members, (o1, o2) -> Integer.compare(o1.getAge(), o2.getAge()));
// 컬렉션 정렬
List<Member> list = new ArrayList<>(List.of(member1, member2));
list.sort(null); // Comparable 기본 정렬
list.sort(new AgeComparator()); // Comparator 지정
Collections.sort(list); // Comparable 기본 정렬
// TreeSet
Set<Member> treeSet1 = new TreeSet<>(); // Comparable 기반
Set<Member> treeSet2 = new TreeSet<>(new AgeComparator()); // Comparator 지정
어떨 때 많이 쓰는가?
| 상황 |
선택 |
| 객체의 자연스러운 기본 순서 정의 |
Comparable |
| 다양한 정렬 기준이 필요 (이름순, 나이순 등) |
Comparator |
TreeSet/TreeMap에 커스텀 객체 사용 |
둘 중 하나 필수 |
| 정렬 기준을 런타임에 결정 |
Comparator (람다 활용) |