리스트를 정렬하기 전에 리스트에 추가할 객체를 정의하고 시작하자.
public class Apple {
private final String name;
private final int weight;
public Apple(String name, int weight) {
this.name = name;
this.weight = weight;
}
public int getWeight() {
return weight;
}
public String getName() {
return name;
}
@Override
public String toString() {
return "Apple{" +
"name='" + name + '\'' +
", weight=" + weight +
'}';
}
}
1. List.sort()
java.util.List.sort()는 List를 정렬하는 데 사용할 수 있다.
Incompatible types. Found: 'java.util.Comparator<T>', required: 'java.util.Comparator<? super Apple>'
정렬을 사용하려 하면 현재는 Comparator.natualOrder()에 빨간 줄이 들어오며 아래와 같은 에러가 뜨는 걸 확인할 수 있다. 이유는
현재 Apple에는 어떤 값을 기준으로 정렬할 건지 선언되어있지 않다!
그럼 Apple에 Comparable Interface를 통해 정렬 기준을 추가해보자.
public class Apple implements Comparable<Apple> {
private final String name;
private final int weight;
public Apple(String name, int weight) {
this.name = name;
this.weight = weight;
}
public int getWeight() {
return weight;
}
public String getName() {
return name;
}
@Override
public String toString() {
return "Apple{" +
"name='" + name + '\'' +
", weight=" + weight +
'}';
}
@Override
public int compareTo(Apple o) {
return this.weight - o.weight;
}
}
/*
결과
Apple{name='A0', weight=0}
Apple{name='A1', weight=1}
Apple{name='A2', weight=2}
Apple{name='A3', weight=3}
Apple{name='A4', weight=4}
*/
Comparable를 상속받으면서 compareTo 메서드를 오버라이딩했고 weight 변수를 통해 정렬하게끔 정의했다. 만약 내림차순으로 정렬을 하고 싶다면 naturalOrder() 대신 reverseOrder()를 사용해주면 됩니다.
2. Collections.sort()
java.util.Collections.sort()는 내부적으로 List.sort()를 사용하고 있다. 그래서 Comparable를 상속받고 있다면 역시 사용 가능하다. 내림차순으로 정렬을 하고 싶다면 sort의 두 번째 인자로 Collections.reverseOrder()를 넣어주면 된다.
public static <T extends Comparable<? super T>> void sort(List<T> list) {
list.sort(null);
}
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class Main {
public static void main(String[] args) {
List<Apple> apples = new ArrayList<>();
for (int i = 0; i < 5; i++) {
apples.add(new Apple("A" + i, i));
}
Collections.sort(apples);
apples.forEach(System.out::println);
}
}
/*
결과
Apple{name='A0', weight=0}
Apple{name='A1', weight=1}
Apple{name='A2', weight=2}
Apple{name='A3', weight=3}
Apple{name='A4', weight=4}
*/
3. Comparator
Apple에 Comparable Interface를 상속받는 게 아닌 Comparator를 익명 클래스로 구현하여 정렬을 해보자
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
public class Main {
public static void main(String[] args) {
List<Apple> apples = new ArrayList<>();
for (int i = 0; i < 5; i++) {
apples.add(new Apple("A" + i, i));
}
apples.sort(new Comparator<Apple>() {
@Override
public int compare(Apple o1, Apple o2) {
return o1.getWeight() - o2.getWeight();
}
});
apples.forEach(System.out::println);
}
}
/*
결과
Apple{name='A0', weight=0}
Apple{name='A1', weight=1}
Apple{name='A2', weight=2}
Apple{name='A3', weight=3}
Apple{name='A4', weight=4}
*/
Apple 클래스에서 Comparable를 제거해도 List.sort() 메서드에서 Comparator를 익명 클래스로 사용해주면 쉽게 정렬이 가능하며 내림차순으로 정렬하고 싶다면 위 코드에서 리턴 부분만 return o2.getWeight() - o1.getWeight(); 로 변경을 해주면 쉽게 정렬이 가능하다.
위에 코드를 보면 익명 클래스로 편하게 구현 가능하지만 코드가 장황한 편이다. 이걸 다시 람다 표현식으로 바꿔 코드를 간결하게 바꿔보자
apples.sort((o1, o2) -> o1.getWeight() - o2.getWeight());
apples.sort(comparing(apple -> apple.getWeight()));
apples.sort(comparing(Apple::getWeight));
익명 클래스를 위와 같이 변경할 수 있다. 제일 아래 :: 기호를 처음 보신 다면 <메서드 참조>라는 키워드로 검색해보시면 됩니다.
추가로 다중 조건으로 정렬을 하려면 어떻게 해야 할까?
익명 클래스로 다중 조건을 정렬해보자.
for (int i = 0; i < 5; i++) {
apples.add(new Apple("A" + i, 5));
}
apples.sort(new Comparator<Apple>() {
@Override
public int compare(Apple o1, Apple o2) {
if (o1.getWeight() == o2.getWeight()) {
return o1.getName().compareTo(o2.getName());
}
return o1.getWeight() - o2.getWeight();
}
});
위 코드는 1. 무게로 비교하고 정렬한다. 2. 무게가 같다면 이름으로 정렬을 한다.
apples.sort(comparing(Apple::getWeight)
.thenComparing(Apple::getName));
위 코드는 comparing 메서드로 무게로 정렬을 하고 무게가 같다고 판단이 되면 이름으로 정렬을 하게 된다. 위 코드는 조건이 늘어나도 thenComparing메서드를 사용해주면 되기 때문에 사용하기 아주 편하다. 하지만 만약 무게는 내림차순으로 정렬하고 싶다면 어떻게 해야 할까?
apples.sort(comparing(Apple::getWeight)
.reversed()
.thenComparing(Apple::getName));
reversed() 메서드를 이용해주면 무게는 내림차순으로 정렬하고 같다면 이름으로 비교하게 된다.
'BE > Java' 카테고리의 다른 글
Thread.run()과 start()의 차이 (1) | 2024.05.05 |
---|---|
[Java] LocalDateTime 정밀도 테스트 실패 (0) | 2023.10.28 |
String vs StringBuffer vs StringBuilder (0) | 2022.11.07 |
[Java] 자바11의 간단한 설명 (2) | 2022.10.31 |
[Java] 객체 지향 설계 5원칙(SOILD) (0) | 2022.08.31 |