1. 객체 정렬?
class Person {
String name;
int weight;
int height;
public Person(String name, int height, int weight) {
this.name = name;
this.weight = weight;
this.height = height;
}
public void print() {
System.out.println(name + " " + height + " " + weight);
}
public int getWeight() {
return weight;
}
public int getHeight() {
return height;
}
}
여기 Person 클래스가 있다.
List<Person> list = new ArrayList<>();
Person 클래스로 이루어진 어레이리스트도 있다.
이 리스트를 정렬하고하자한다.
name을 기준으로 정렬을 해야할까 weight를 기준으로 정렬을 해야할까?
우리는 이 문제를 Comparable이나 Comparator를 통해서 해결할 수 있다.
1. Comparable
정렬하고자 하는 객체의 클래스에 Comparable 인터페이스를 구현하는 방법이다.
물론 그 클래스에 Comparable 인터페이스를 구현할 수 있다면 말이다.
// 정렬 대상 클레스에 인터페이스를 구현할 수 있다면 Comparable 사용 가능
class Person implements Comparable<Person> {
String name;
int weight;
int height;
public Person(String name, int height, int weight) {
this.name = name;
this.weight = weight;
this.height = height;
}
public void print() {
System.out.println(name + " " + height + " " + weight);
}
public int getWeight() {
return weight;
}
public int getHeight() {
return height;
}
@Override
public int compareTo(Person p) {
// 오름차순: this 객체 - 인자로 넘어온 객체
// 내림차순: 인자로 넘어온 객체 - this 객체
return this.height - p.height; // 오름차순 정렬
}
}
Collections.sort(list);
Comparable 인터페이스의 compareTo 메소드를 구현하면 된다.
위 코드는 height를 기준으로 오름차순 정렬의 예시다.
만약 1순위로 height를 기준으로 오름차순 정렬하고
height가 같은 객체가 있다면
2순위로 weight를 기준으로 내림차순 정렬하고 싶다면?
class Person implements Comparable<Person> {
String name;
int weight;
int height;
public Person(String name, int height, int weight) {
this.name = name;
this.weight = weight;
this.height = height;
}
public void print() {
System.out.println(name + " " + height + " " + weight);
}
public int getWeight() {
return weight;
}
public int getHeight() {
return height;
}
@Override
public int compareTo(Person p) {
// this 객체 > 인자로 넘어온 객체 => return 1이라는것은
// this 객체 - 인자로 넘어온 객체 > 0 => 오름차순
if (this.height > p.height) return 1;
else if (this.height == p.height) { // height가 같다면
// this 객체 < 인자로 넘어온 객체 => return 1이라면
// this 객체 - 인자로 넘어온 객체 < 0 => 내림차순
if (this.weight < p.weight) return 1; // weight를 내림차순으로
}
return -1;
}
}
이렇게 하면 된다.
2. Comparator
정렬하고자 하는 객체의 클래스에 Comparable 인터페이스를 구현할 수 없을때 사용하는 방법이다.
혹은 Comprable 인터페이스를 통해 이미 정렬기준이 정해져있지만 다른 기준으로 정렬하고 싶을때 사용하는 방법이다.
// 정렬 대상 클레스에 인터페이스를 구현할 수 없다면
// 혹은 Comparable을 통해 이미 정해져있는 정렬 기준과 다르게 정렬하고 싶다면
class Person {
String name;
int weight;
int height;
public Person(String name, int height, int weight) {
this.name = name;
this.weight = weight;
this.height = height;
}
public void print() {
System.out.println(name + " " + height + " " + weight);
}
public int getWeight() {
return weight;
}
public int getHeight() {
return height;
}
}
Person 클래스는 동일하다.
우리는 Comparator라는 일종의 정렬기준을 정의한 객체를 만들어서 Collections.sort()의 인자로 넣어주어야 한다.
public static <T> void sort(List<T> list, Comparator<? super T> c) {
list.sort(c);
}
Collections.sort 함수를 까보면 첫번째로 정렬 할 리스트와 두번째로 정렬 기준인 Comparator를 받는 것을 볼 수 있다.
Collections.sort(list, new Comparator<Person>() {
@Override
public int compare(Person o1, Person o2) {
// 오름차순
return o1.height - o2.height;
}
});
Comparator객체를 한번쓰고 버릴것 이니 익명클래스로 넣어주었다.
저 익명클래스의 객체는 Comparator 인터페이스를 구현받고있기에 compare 함수를 오버라이드하고있다.
정렬 기준이 2개 이상일 때도 Comparable과 동일하게 해주면 된다.
Collections.sort(list, new Comparator<Person>() {
@Override
public int compare(Person o1, Person o2) {
// height 기준 오름차순
if (o1.height > o2.height) return 1;
else if (o1.height == o2.height) {
// height가 같다면 weight 기준으로 내림차순
if (o1.weight < o2.weight) return 1;
}
return -1;
}
});
Comparator를 람다함수로 조금더 간단하게 표현할 수 있다.
Collections.sort(list, (a, b) -> a.getHeight() - b.getHeight());
stream을 쓰면 더더더 간단하게 표현할 수 있다.
list.sort(Comparator.comparing(Person::getHeight));
stream을 사용했을때 2개 이상의 기준을 적용하고 싶다면
list.sort(Comparator.comparing(Person::getHeight).thenComparing(Person::getWeight));
이렇게 thenComparing을 통해 이어주면 된다.
하나의 조건은 역순으로 하고싶다면 .reversed()를 붙혀주면 되는데 주의 할 것이
list.sort(Comparator.comparing(Person::getHeight).thenComparing(Person::getWeight).reversed());
이렇게 뒤에 reversed()를 바로 붙이면 height에 대한 정렬도 reversed()에 영향을 받아서 두가지 기준 다 내림차순 정렬이 돼 버린다.
두번째 기준만 내림차순으로 하고 싶다면
Comparator<Person> reverseCompare = Comparator.comparing(Person::getWeight).reversed();
list.sort(Comparator.comparing(Person::getHeight).thenComparing(reverseCompare));
이렇게 reverse용 Comparator를 따로 만들어서 넣어주어야 한다.
참고:
'Java' 카테고리의 다른 글
[GC] 가비지와 GC, 메모리 누수에 대해 ARABOZA (1) | 2024.09.14 |
---|---|
[Java] 해시/해시테이블이란? (0) | 2021.07.12 |
[Java] 제네릭(Generic) (0) | 2021.07.11 |
[Java] Garbage Collection (4) | 2021.07.01 |
[Java] Thread/MultiThread 4 - 동시성 문제 (0) | 2021.06.29 |