자바와 같은 객체 지향 언어를 사용하면, 객체들을 정렬해야 하는 경우가 생깁니다.
EX)
여러 경우 중, 예를 들어 학생들을 나이순으로 나열해야 한다고 생각했을 때 학생 클래스를 생성해보면 이렇게 됩니다.
public class Student{
private String name;
private int age;
public Student(String name, int age){
this.name = name;
this.age = age;
}
}
학생들이 이렇게 있다고 가정했을 때, 존 김초코 밥 앨리스 순으로 나열해야합니다.
이제 학생들을 어떻게 나이순으로 정렬할까요?
List<Student> students = new ArrayList<>();
students.add(new Student("Alice", 15));
students.add(new Student("bob", 23));
students.add(new Student("kim Choco", 18));
students.add(new Student("john", 55));
제목과 같이 두 가지 방법, Comparable 과 Comparator 에 대해서 알아볼 예정입니다.
단순한 숫자나 문자와 같은 기본형(primitive)데이터는 자바가 일반적인 대소관계(1 보다 2가 크다, A보다 B가 크다 ) 에 따라 정렬해줍니다.
예를 들어 학생의 나이를 별도의 배열로 생성하여 Arrays.sort() 메서드를 사용하면 됩니다.
int[] ages = {15,23,18,55};
Arrays.sort(ages);
System.out.println(Arrays.toString(ages));
// 출력 : [15, 18, 23, 55]
하지만, 특정 타입의 객체는 기본형 데이터와 달라 정렬 기준이 없으면 정렬을 할 수 없으며, 정렬 기준을 정의하여 알려주어야 합니다.
그 첫번째 방법이 Comparable 입니다.
( 정렬하려 했을 시 컴파일 에러 일어남 )
Collections.sort(students); // error !!!
객체의 정렬 기준을 정의하는 방법 중 하나로,
자바에서 기본적으로 제공하고 있는 Comparable 인터페이스를 구현하도록 변경하는 것 입니다.
Student 클래스에 적용하면 아래와 같이 됩니다.
class Student implements Comparable<Student>{
private String name;
private int age;
public Student(String name, int age){
this.name = name;
this.age = age;
}
@Override
public int compareTo(Student o) {
return this.age - o.age;
}
}
Comparable 인터페이스의 compareTo() 메서트를 통해 인자로 넘어온 같은 타입의 다른 객체와 대소 비교 가능해졌습니다.
이제 Collections.sort() 메서드에는
Comparable 인터페이스를 구현한 Comparable 타입의 Student 객체의 리스트가
인자로 넘어가기 때문에 더 이상 컴파일 에러가 발생하지 않습니다.
(위에 Comparable 을 구현하기 전의 빨간줄이 없어졌음을 알 수 있지용 )
정렬 후 출력
Collections.sort(students);
// [name = Aliceage = 15 ]
// [name = kim Chocoage = 18 ]
// [name = bobage = 23 ]
// [name = johnage = 55 ]
정의
// Integer class
public final class Integer extends Number implements Comparable<Integer> { ... }
// String class
public final class String implements java.io.Serializable, Comparable<String>, CharSequence { ... }
Ex) Integer, Double 클래스: 오름차순 정렬
Ex) String 클래스: 사전순 정렬
구현 방법
사용 방법
1. Arrays.sort()
2. Collections.sort()
정렬 대상 클래스의 코드를 직접 수정할 수 없는 경우에는 어떻게 객체의 정렬 기준을 정의할 수 있을까요?
또는, 정렬하고자 하는 객체는 이미 존재하고 있는 정렬 기준과 다른 정렬 기준으로 정렬하고 싶을 때는 어떻게 해야할까요?
바로바로 Comparator 인터페이스의 구현체를
Arrays.sort()나 Collections.sort()와 같은 정렬 메서드의 추가 인자로 넘기면,
새로운 정렬 기준으로 객체를 정렬할 수 있습니다.
Comparator<Student> comparator = new Comparator<Student>(){
@Override
public int compare(Student o1, Student o2) {
return o1.getAge() - o2.getAge();
}
};
Collections.sort(students, comparator);
결과
System.out.println(students);
//[name = Alice, age = 15 ]
// [name = kim Choco, age = 18 ]
// [name = bob, age = 23 ]
// [name = john, age = 55 ]
위 코드는 Comparator 객체를 Collections.sort() 메서드의 두번째 인자로 넘겨 이전과 동일한 정렬 결과를 얻을 수 있습니다.
이렇게 Comparator 객체를 인자로 넘기면, 정렬 대상 객체가 Comparable 인터페이스 구현 여부와 상관없이
넘어온 Comparator 구현체의 compare() 메서드 기준으로 정렬을 수행합니다.
정의
구현 방법
사용 방법
두 번째 인자로 Comparator interface를 받는 경우
PriorityQueue(int initialCapacity, Comparator<? super E> comparator)
Comparator 객체는 메서드가 하나 뿐인 함수형 인터페이스를 구현하기 때문에 람다 함수로 대체가 가능
Collections.sort(students, (a, b) -> a.getAge() - b.getAge());
System.out.println(students);
// [name = Alice, age = 15 ]
// [name = kim Choco, age = 18 ]
// [name = bob, age = 23 ]
// [name = john, age = 55 ]
참고
https://www.daleseo.com/java-comparable-comparator/
https://st-lab.tistory.com/243
https://gmlwjd9405.github.io/2018/09/06/java-comparable-and-comparator.html