Java/Java이론

List 정렬과 Comparator/Comparable 인터페이스 활용

P_eli 2024. 11. 6. 23:50
728x90
반응형

Java에서 리스트나 컬렉션 내 요소를 정렬하는 것은 중요한 기술 중 하나입니다. 컬렉션의 요소가 기본적으로 정렬 가능한지 여부에 따라 두 가지 인터페이스, Comparable과 Comparator,를 사용합니다. 이를 활용하면 단순한 정렬부터 복잡한 다중 필드 정렬까지 구현할 수 있습니다. 아래에서 이 두 인터페이스를 비교하고, Java 8 이후의 기능 확장에 대해 설명하겠습니다.

1. Comparable 인터페이스

Comparable 인터페이스는 객체 자체에 정렬 기준을 정의할 때 사용됩니다. 즉, 객체에 내장된 정렬 기능을 설정할 수 있습니다. Comparable 인터페이스는 단일 정렬 기준만을 제공하기 때문에 간단한 정렬 작업에 적합합니다.

구현 방법:

  1. 클래스에 Comparable<T> 인터페이스를 구현합니다.
  2. compareTo 메서드를 오버라이드하여 정렬 기준을 정의합니다.

예제 코드

public class Student implements Comparable<Student> {
    private String name;
    private int score;

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

    @Override
    public int compareTo(Student other) {
        // 점수를 기준으로 오름차순 정렬
        return Integer.compare(this.score, other.score);
    }

    @Override
    public String toString() {
        return "Student{name='" + name + "', score=" + score + "}";
    }
}

 

이제 List<Student>를 정렬할 때 Collections.sort() 또는 list.sort() 메서드를 호출하면 score를 기준으로 정렬됩니다.

2. Comparator 인터페이스

Comparator는 객체 외부에 정렬 기준을 제공할 때 사용됩니다. 즉, 기존 클래스의 정렬 방식을 변경하지 않고도 다양한 정렬 기준을 적용할 수 있습니다. Comparator는 다중 필드 정렬이나 복잡한 정렬 로직을 구현할 때 유용합니다.

구현 방법:

  1. Comparator<T> 인터페이스를 구현하거나, 정적 메서드로 구현된 람다식을 사용합니다.
  2. compare 메서드를 오버라이드하여 정렬 기준을 정의합니다.

예제 코드

import java.util.*;

public class Main {
    public static void main(String[] args) {
        List<Student> students = Arrays.asList(
            new Student("Alice", 85),
            new Student("Bob", 92),
            new Student("Charlie", 78)
        );

        // 점수 기준으로 내림차순 정렬
        students.sort(Comparator.comparingInt(Student::getScore).reversed());

        // 이름 기준으로 정렬
        students.sort(Comparator.comparing(Student::getName));

        // 다중 기준 정렬: 점수 내림차순 후 이름 오름차순
        students.sort(
            Comparator.comparingInt(Student::getScore).reversed()
                      .thenComparing(Student::getName)
        );

        students.forEach(System.out::println);
    }
}

 

3. Java 8 이후의 Comparator 확장 메서드

Java 8부터 Comparator 인터페이스는 다양한 메서드를 통해 더욱 강력해졌습니다. 대표적인 메서드는 comparing, thenComparing, reversed입니다. 이를 사용하면 코드가 더욱 직관적이며 간결해집니다.

확장 메서드 예시:

  • Comparator.comparing(Function<T, U> keyExtractor): 특정 키를 기준으로 정렬합니다.
  • thenComparing(Function<T, U> keyExtractor): 첫 번째 정렬 기준이 같은 경우 두 번째 기준으로 정렬합니다.
  • reversed(): 정렬 결과를 뒤집습니다.

예제 코드

students.sort(Comparator.comparing(Student::getScore)
                        .thenComparing(Student::getName)
                        .reversed());

 

4. 사용자 정의 객체 리스트 정렬 실습

아래는 Comparator와 Comparable을 활용하여 사용자 정의 객체 리스트를 정렬하는 실습 코드입니다.

실습 코드

public class Main {
    public static void main(String[] args) {
        List<Student> students = Arrays.asList(
            new Student("Alice", 90),
            new Student("David", 95),
            new Student("Bob", 90),
            new Student("Charlie", 85)
        );

        // 점수 오름차순 후 이름 오름차순 정렬
        students.sort(Comparator.comparingInt(Student::getScore)
                                .thenComparing(Student::getName));

        students.forEach(System.out::println);
    }
}

 

5. 정리

  • Comparable은 클래스 내부에 내장된 단일 정렬 기준을 정의할 때 사용됩니다.
  • Comparator는 클래스 외부에서 다양한 정렬 기준을 제공할 때 사용되며, 다중 필드 정렬을 구현하기에 적합합니다.
  • Java 8 이후에는 람다식과 메서드 참조, 다양한 Comparator 확장 메서드를 활용하여 더 간결하고 읽기 쉬운 코드를 작성할 수 있습니다.
728x90
반응형