Java
[JAVA] Comparable, Comparator
개바리여리
2025. 12. 13. 19:08
Comparable 인터페이스는 compareTo 메서드를 재정의하여 두 객체를 비교할때 사용된다.
"객체 스스로가 정렬 기준을 정의하도록 만드는 인터페이스"
String, Date, Integer, Character, Double 등의 wrapper 클래스는 이미 Comparable 인터페이스가 구현되어 있다.
public interface Comparable<T> {
int compareTo(T o);
}
자기 자신(this) 과 다른 객체 (o)를 비교한다.
this < o : 음수 리턴
this == 0 : 0 리턴
this > 0 : 양수리턴
* Comparable 구현이 안되어 있으면 정렬이 불가능하다.
public class Person implements Comparable<Person> {
private String name;
private int age;
@Override
public int compareTo(Person o) {
// 나이 오름차순
return Integer.compare(this.age, o.age);
//내림차순이라면 아래와 같이
//return Interger.compare(o.age, this.age);
}
@Override
public String toString() {
return name + "(" + age + ")";
}
}
public class ComparableTest {
public static void main(String[] args) {
List<Person> list = new ArrayList<>();
list.add(new Person("철수", 30));
list.add(new Person("영희", 25));
list.add(new Person("민수", 40));
list.add(new Person("지훈", 25));
System.out.println("정렬 전:");
System.out.println(list);
Collections.sort(list);
System.out.println("정렬 후 (나이 오름차순):");
System.out.println(list);
}
}
Collections.sort(list)를 호출하면
정렬 과정에서 필요한 순간마다 Person.compareTo(other)를 반복 호출해서
그 리턴값(음수/0/양수)을 기준으로 순서를 바꾼다. 값의 크기보다는 양수냐 음수냐가 중요함.
Comparator
정렬 기준을 객체 바깥에서 주입하는 인터페이스
public interface Comparator<T> {
int compare(T o1, T o2);
}
- o1 과 o2 두 객체를 외부에서 비교
- 객체 자신은 아무것도 모름
- “이번엔 이렇게 정렬해줘” 하고 그때그때 기준을 바꿈
| Comparable | Comparator | |
| 위치 | 클래스 내부 | 클래스 외부 |
| 메서드 | compareTo(this vs o) | compare(o1 vs o2) |
| 정렬 기준 | 고정 (자연 정렬) | 유동적 (상황별) |
| 개수 | 보통 1개 | 여러 개 |
| 수정 영향 | 클래스 수정 필요 | 클래스 수정 없음 |
| 실무 용도 | 도메인 기본 정렬 | 화면 / 조건 / 버튼 |
Collections.sort(list, new Comparator<Person>(){
@Override
public int compare(Person a, Person b){
return a.getName().compareTo(b.getName());
}
});
실습 예제
public class Order implements Comparable<Order>{
private Long id;
private String customerName;
private int totalPrice;
private OrderStatus status;
private LocalDateTime orderDate;
public Order(Long id, String customerName, int totalPrice,
OrderStatus status, LocalDateTime orderDate) {
this.id = id;
this.customerName = customerName;
this.totalPrice = totalPrice;
this.status = status;
this.orderDate = orderDate;
}
//기본정렬 : 주문일 최신순
@Override
public int compareTo(Order o) {
return o.orderDate.compareTo(this.orderDate);
}
public String getCustomerName() { return customerName; }
public int getTotalPrice() { return totalPrice; }
public OrderStatus getStatus() { return status; }
public LocalDateTime getOrderDate() { return orderDate; }
@Override
public String toString() {
return "Order{" +
"id=" + id +
", customer='" + customerName + '\'' +
", price=" + totalPrice +
", status=" + status +
", date=" + orderDate +
'}';
}
}
public enum OrderStatus {
READY("주문접수"), //주문접수
PAID("결제완료"), //결제완료
SHIPPED("출고"), //출고
DONE("완료"); //완료
private final String description;
OrderStatus(String description){
this.description = description;
}
public String getDescription(){
return this.description;
}
}
public class OrderSortTest {
public static void main(String[] args){
List<Order> orders = new ArrayList<>();
orders.add(new Order(1L, "김철수", 30000, OrderStatus.PAID,
LocalDateTime.now().minusHours(2)));
orders.add(new Order(2L, "이영희", 120000, OrderStatus.READY,
LocalDateTime.now().minusDays(1)));
orders.add(new Order(3L, "박민수", 50000, OrderStatus.SHIPPED,
LocalDateTime.now().minusHours(5)));
orders.add(new Order(4L, "김철수", 70000, OrderStatus.DONE,
LocalDateTime.now().minusDays(2)));
System.out.println("=== 기본 정렬 (주문일 최신순) ===");
Collections.sort(orders);
orders.forEach(System.out::println);
//금액 높은순 정렬 (Comparator)
System.out.println("\n=== 금액 높은 순 ===");
orders.sort(
Comparator.comparing(Order::getTotalPrice).reversed()
);
orders.forEach(System.out::println);
System.out.println("\n=== 상태별 정렬 ===");
Map<OrderStatus, Integer> statusOrder = Map.of(
OrderStatus.READY, 1,
OrderStatus.PAID, 2,
OrderStatus.SHIPPED, 3,
OrderStatus.DONE, 4
);
orders.sort(
Comparator.comparing(o -> statusOrder.get(o.getStatus()))
);
// status 정렬하는데 같으면 orderDate 기준으로 내림차순 정렬
System.out.println("\n=== 상태 → 주문일 최신순 ===");
orders.sort(
Comparator.comparing(Order::getStatus)
.thenComparing(Order::getOrderDate, Comparator.reverseOrder())
);
}
}