Comparator 인터페이스
Coddy Java 여정의 객체 지향 프로그래밍 섹션에 포함된 레슨 — 87개 중 45번째.
Comparable이 클래스의 자연스러운 정렬 순서를 정의하는 반면, 때로는 객체를 다른 방식으로 정렬해야 할 때가 있습니다. Comparator 인터페이스를 사용하면 원래 클래스를 수정하지 않고도 별도의 비교 로직을 만들 수 있습니다.
Comparator는 동일한 타입의 두 객체를 비교하는 외부 객체입니다. 이는 여러 정렬 옵션을 원하거나 클래스 자체를 수정할 수 없을 때 유용합니다:
import java.util.Comparator;
class NameComparator implements Comparator<Person> {
@Override
public int compare(Person p1, Person p2) {
return p1.getName().compareTo(p2.getName());
}
}
class AgeComparator implements Comparator<Person> {
@Override
public int compare(Person p1, Person p2) {
return p1.getAge() - p2.getAge();
}
}그런 다음 비교자를 정렬 메서드에 전달할 수 있습니다:
List<Person> people = new ArrayList<>();
people.add(new Person("Charlie", 30));
people.add(new Person("Alice", 25));
Collections.sort(people, new NameComparator()); // 이름순으로 정렬
Collections.sort(people, new AgeComparator()); // 나이순으로 정렬간결한 코드를 위해, Comparator는 함수형 인터페이스이므로 람다 표현식을 사용할 수 있습니다:
Collections.sort(people, (p1, p2) -> p1.getName().compareTo(p2.getName()));핵심적인 차이점: Comparable은 비교 대상이 되는 클래스에 의해 구현되며 하나의 자연스러운 순서(natural order)를 정의하는 반면, Comparator는 무제한의 사용자 정의 정렬을 정의할 수 있는 별도의 클래스입니다.
챌린지
쉬움Comparator 인터페이스의 강력함을 보여주는 직원 정렬 시스템을 구축해 보겠습니다. Employee 클래스 자체를 수정하지 않고도 급여별, 이름별 등 다양한 방식으로 직원을 정렬하기 위해 여러 개의 comparator를 만들 것입니다.
코드는 다음 네 개의 파일로 구성됩니다:
Employee.java: 세 개의 private 필드name(String),department(String),salary(double)를 가진 직원을 나타내는 클래스를 만듭니다. 모든 필드를 초기화하는 생성자와 각 필드에 대한 getter 메서드를 포함하세요.toString()을 오버라이드하여[name] ([department]) - $[salary]형식을 반환하도록 합니다.SalaryComparator.java: 직원을 급여 기준 내림차순(높은 급여가 먼저 오도록)으로 정렬하는 comparator를 만듭니다.Comparator<Employee>인터페이스와 그compare()메서드를 구현하세요. 급여 값의 안전한 비교를 위해Double.compare()를 사용하세요.NameComparator.java: 직원을 이름 기준 알파벳 오름차순(A부터 Z까지)으로 정렬하는 또 다른 comparator를 만듭니다.Comparator<Employee>를 구현하고 비교를 위해 String의compareTo()메서드를 사용하세요.Main.java: 직원 리스트를 생성하고 작성한 comparator를 사용하여 정렬함으로써 모든 것을 하나로 합칩니다. 세 명의 직원에 대한 입력을 받게 되며, 각 줄은name,department,salary형식입니다.직원들의
ArrayList를 생성한 다음, 두 가지 정렬 방식을 모두 보여주세요:- 먼저,
SalaryComparator를 사용하여 급여순으로 정렬하고 각 직원을 출력합니다. - 빈 줄을 하나 출력합니다.
- 그런 다음
NameComparator를 사용하여 이름순으로 정렬하고 각 직원을 출력합니다.
- 먼저,
각각 name,department,salary 형식의 직원 데이터를 포함하는 세 줄의 입력을 받게 됩니다.
예를 들어, 입력 줄은 다음과 같을 수 있습니다: Alice,Engineering,75000.0
comparator 파일에서는 java.util.Comparator를 임포트하고, Main 파일에서는 java.util.ArrayList, java.util.Collections, java.util.Scanner를 임포트하는 것을 잊지 마세요. comparator를 사용하면 외부에서 여러 정렬 전략을 정의할 수 있다는 점에 주목하세요. Employee 클래스는 자신이 어떻게 정렬될지에 대해 전혀 알 필요가 없습니다!
치트 시트
Comparator 인터페이스를 사용하면 원래 클래스를 수정하지 않고도 객체 정렬을 위한 외부 비교 로직을 만들 수 있습니다. 이는 여러 가지 정렬 옵션이 필요할 때 유용합니다.
Comparator는 compare() 메서드를 구현하여 동일한 타입의 두 객체를 비교합니다:
import java.util.Comparator;
class NameComparator implements Comparator<Person> {
@Override
public int compare(Person p1, Person p2) {
return p1.getName().compareTo(p2.getName());
}
}정렬 메서드에 comparator를 전달합니다:
Collections.sort(people, new NameComparator());Comparator는 함수형 인터페이스이므로 람다 표현식을 사용하여 간결한 코드를 작성할 수 있습니다:
Collections.sort(people, (p1, p2) -> p1.getName().compareTo(p2.getName()));숫자 값을 비교할 때는 안전한 비교를 위해 Double.compare()와 같은 래퍼 클래스 메서드를 사용하세요:
class AgeComparator implements Comparator<Person> {
@Override
public int compare(Person p1, Person p2) {
return p1.getAge() - p2.getAge();
}
}주요 차이점: Comparable은 클래스 자체 내에서 하나의 자연스러운 순서를 정의하는 반면, Comparator는 외부에서 무제한으로 사용자 정의 순서를 정의할 수 있는 별도의 클래스입니다.
직접 해보기
import java.util.ArrayList;
import java.util.Collections;
import java.util.Scanner;
class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// 입력으로부터 세 명의 직원을 읽어옵니다
// 각 줄의 형식: name,department,salary
String line1 = scanner.nextLine();
String line2 = scanner.nextLine();
String line3 = scanner.nextLine();
// TODO: 각 줄을 파싱하고 Employee 객체를 생성하세요
// 힌트: 값을 분리하려면 split(",")를 사용하세요
// TODO: 직원들의 ArrayList를 생성하고 세 명을 모두 추가하세요
// TODO: SalaryComparator를 사용하여 급여순으로 정렬하고 각 직원을 출력하세요
// 힌트: Collections.sort(list, comparator)를 사용하세요
// TODO: 빈 줄을 출력하세요
// TODO: NameComparator를 사용하여 이름순으로 정렬하고 각 직원을 출력하세요
}
}
이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.
객체 지향 프로그래밍의 모든 레슨
4상속
상속의 기초 (extends)super 키워드메서드 오버라이딩 (@Override)생성자 체이닝Object 클래스단일 및 다중 레벨 상속다중 클래스 상속이 불가능한 이유요약 - 직원 계층 구조7특별한 메서드와 Object 클래스
toString() 메서드equals()와 hashCode()clone() 메서드compareTo()와 ComparableComparator 인터페이스요약 - 커스텀 정렬