개발 공부/Java | SpringBoot

[Java/ChatGPT] Day 15: 컬렉션 정렬 (Comparable & Comparator)

dev.jelee 2025. 6. 23. 17:37

[ 학습 목표 ]

  • Collections.sort()를 사용해 리스트 정렬 방법을 익힌다.
  • Comparable 인터페이스를 구현하여 기본 정렬 기준을 만든다.
  • Comparator 인터페이스를 사용해 동적으로 정렬 기준을 바꿔본다.

[ 이론 ]

1. 기본 정렬 : Collections.sort(List<T>)

  • 기본 타입(String, Integer 등)은 정렬 기준이 이미 정의되어 있다.
import java.util.*;

public class SortExample {
  public static void main(String[] args) {
    List<String> fruits = new ArrayList<>();
    fruits.add("banana");
    fruits.add("apple");
    fruits.add("orange");

    System.out.println(fruits); // Collections.sort() 전
    
    Collections.sort(fruits);

    System.out.println(fruits); // Collections.sort() 후
  }
}

 

2. 사용자 정의 클래스 정렬 : Comparable

  •  implements Coparable<Student> { ... } : 제너릭에는 비교 대상의 타입을 작성
public class Student implements Comparable<Student> { // Comparable<T> 제너릭 안에는 비교 대상의 타입
  String name;
  int score;

  // 생성자
  Student(String name, int score) {
    this.name = name;
    this.score = score;
  }

  // 정렬 기준 정의: 점수 오름차순
  // compareTo 메서드 재정의
  @Override
  public int compareTo(Student other) {
    return this.score - other.score; // this를 기준으로 other보다 음수면 앞에, 크면 뒤에 배치
  }

  public String toString() {
    return name + " (" + score + ")";
  }
}
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class Main {
  public static void main(String[] args) {
    List<Student> list = new ArrayList<>();
    list.add(new Student("철수", 85));
    list.add(new Student("영희", 95));
    list.add(new Student("민수", 75));
    
    Collections.sort(list);

    for (Student s : list) {
      System.out.println(s); // 숫자 순으로 정렬되어 나옴
    }
  }
}

 

3. 동적 정렬 : Comparator

  • 기준을 여러 개 정의하고 싶을 때 사용
public class Student {
  String name;
  int score;

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

  @Override
  public String toString() {
    return name + " (" + score + "점)";
  }
}
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

public class Main {
  public static void main(String[] args) {
    // Student 객체 리스트 생성
    List<Student> students = new ArrayList<>();
    students.add(new Student("영희", 90));
    students.add(new Student("철수", 85));
    students.add(new Student("민수", 95));

    // 이름 기준 오름차순 정렬 (Comparator 사용) - 정렬을 계산하는 메서드만 있는 객체일 뿐
    Comparator<Student> nameComparator = new Comparator<Student>() {
      @Override
      public int compare(Student s1, Student s2) {
        return s1.name.compareTo(s2.name); // 이름 기준 정렬
      }
    };

    // 정렬 적용
    Collections.sort(students, nameComparator);

    // 출력
    for (Student s : students) {
      System.out.println(s); // 민수, 영희, 철수. 이름 기준으로 정렬되어 출력
    }
  }
}

 

4. 람다식으로 간단히 가능

  • 동적 정렬 : Comparator의 Student class의 내용은 동일. Main class에서 정렬하는 방식만 다름.
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class Main {
  public static void main(String[] args) {
    // Student 객체 리스트 생성
    List<Student> students = new ArrayList<>();
    students.add(new Student("영희", 90));
    students.add(new Student("철수", 85));
    students.add(new Student("민수", 95));

    // 람다식으로 오름차순
    Collections.sort(students, (s1, s2) -> s1.name.compareTo(s2.name));

    // 출력
    for (Student s : students) {
      System.out.println(s); // 민수, 영희, 철수. 이름 기준으로 정렬되어 출력
    }
  }
}

 

5. 핵심 요약

인터페이스 목적 사용위치
Comparable<T> 객체 자체에 기본 정렬 기준을 정의 클래스 내부
Comparator<T> 정렬 기준을 외부에서 동적으로 정의 외부 클래스, 람다 등

[ 실습 ]

🧩 오늘의 과제

Book 클래스를 만들고, 제목과 출판 연도를 멤버 변수로 갖는다.
그리고 아래 두 기준으로 정렬해보기:

 

1. 출판 연도 기준 오름차순 (Comparable 사용)

2. 제목 기준 내림차순 (Comparator 사용)

 

▼ 내가 작성한 코드

  • Book 클래스는 Comparable<T> 인터페이스를 구현한 구현 클래스로 만들고, 클래스 내부에 compareTo 메서드를 재정의하여 연도별로 오름차순이 되도록 작성했다.
  • Main 클래스는 순서대로 연도별로 오름차순을 만든 것을 출력하고, 그 다음 제목을 기준으로 내림차순 시킨 것을 출력했다.
  • 제목을 내림차순하는 방식은 Main 클래스 내부에 Comparator을 사용하여 사용자 정의 정렬을 만들었다. 내용은 compare() 메서드를 재정의하는데 b1, b2 임시 변수를 만들어서 매개변수에 작성하고, 블럭 안에는 b2.title 기준으로 compareTo() 메서드를 사용해서 b1.title과 비교하여 내림차순이 되도록 작성.
  • 세번째는 람다식으로 제목을 내림차순 기준으로 한 코드 작성해보았다.
public class Book implements Comparable<Book> {
  String title;
  int year;

  public Book(String title, int year) {
    this.title = title;
    this.year = year;
  }

  @Override
  public int compareTo(Book other) {
    return this.year - other.year; // 오름차순
  }

  public String toString() {
    return title + "( " + year + "년)";
  }
}
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

public class Main {
  public static void main(String[] args) {
    List<Book> books = new ArrayList<>();
    books.add(new Book("Java 입문 가이드", 2018));
    books.add(new Book("Effective Java", 2020));
    books.add(new Book("알고리즘 문제 해결 전략", 2016));
    books.add(new Book("클린 코드", 2010));
    books.add(new Book("모던 자바 인 액션", 2021));

    // 출판 연도 기준 오름차순 출력
    System.out.println("---------- 출판 연도 기준 오름차순 출력 ----------");
    Collections.sort(books);
    for (Book b : books) {
      System.out.println(b);
    }

    // 제목 기준 내림차순 출력 - Comparator 사용
    System.out.println("---------- 제목 기준 내림차순 출력 ----------");
    Comparator<Book> nameComparator = new Comparator<Book>() {
      @Override
      public int compare(Book b1, Book b2) {
        return b2.title.compareTo(b1.title);
      }
    };
    Collections.sort(books, nameComparator);
    for (Book b : books) {
      System.out.println(b);
    }
    
    // 제목 기준 내침차순 출력 - 람다식으로
    System.out.println("---------- 제목 기준 내림차순 출력 - 람다식 계산 ----------");
    Collections.sort(books, (b1, b2) -> b2.title.compareTo(b1.title));
    for (Book b : books) {
      System.out.println(b);
    }
  }
}

[ 메모 ]

  • 학원에서 배웠는지, 안 배웠는지 기억에 없던 방식. 그래서 필기하고 코드 작성해보고 이해하는데 2시간 가량 걸렸다.
  • 자주 사용해봐야지 익숙해질 거 같은데, 현재로는 어떻게 사용하는지를 이해했다.