2024. 3. 10. 17:59ㆍJava/Effective Java
Comparable 인터페이스 내에 선언된 유일한 메서드인 compareTo는 동치성 비교에 더해 순서 비교까지 가지고 있습니다.
Comparable을 구현한 클래스를 담은 배열은 Arrays.sort()
를 이용하여 정렬할 수 있습니다.
compareTo 메서드 일반 규약입니다.
- 현재객체가 주어진 객체보다 작으면 -1, 같으면 0, 크면 1를 반환합니다. (현재객체와 비교할 수 없는 타입이 주어지는 경우에는
ClassCastException
을 반환합니다.) - x.compareTo(y) == -y.compareTo(x)
x.compareTo(y) > 0 && y.compareTo(z) 일 경우
,x.compareTo(z) > 0
를 만족해야 합니다.x.compareTo(y) == 0
일 경우,x.compareTo(z) == y.compareTo(z)
를 만족해야 합니다.x.compareTo(y) == 0
일 경우,x.equals(y)
여야 합니다.
compareTo 규약을 지킬 경우, 비교를 활용한 클래스인 TreeSet, TreeMap, 정렬 등을 활용할 수 있습니다.
정렬된 컬렉션의 경우, 동치성 비교에 equals가 아닌 compareTo 를 사용합니다.
compareTo의 일반 규약중 맨 마지막에 쓰여진, x.compareTo(y) == 0
인 경우, x.equals(y) == true
를 만족하도록 정의하자에 대해서 살펴봅시다.
BigDecimal에서 "1.0"과 "1.00" 입력에 대한 compareTo 비교값은 0을 반환하지만, equals 결과는 false를 반환하고 있습니다.
BigDecimal b1 = new BigDecimal("1.0"); BigDecimal b2 = new BigDecimal("1.00"); System.out.println(b1.equals(b2)); // false System.out.println(b1.compareTo(b2)); // 0
이러한 이유로, HashSet에 넣은 결과와
Set<BigDecimal> hashSet = new HashSet<>(); hashSet.add(b1); hashSet.add(b2); System.out.println(hashSet); // [1.0, 1.00]
TreeSet에 넣은 결과가 달라지게 됩니다.
Set<BigDecimal> treeSet = new TreeSet<>(); treeSet.add(b1); treeSet.add(b2); System.out.println(treeSet); // [1.0]
이 부분에 대해 유의하고, compareTo를 규약에 맞춰 정의하는 필요성에 대해 고려해보는 것이 좋습니다.
정수나 실수 primitive 타입에 대한 비교연산은 < 나 > 같은 관계 연산자를 쓰지 않아야 합니다.
(보이게도 거추장 스럽고 오류를 발생시키기도 합니다.)
compareTo 메서드에서 필드값을 비교할 때에는
- 박싱된 기본 타입 클래스의 정적 메서드(
Float.compare
등..)를 이용하거나 - Comparator 인터페이스가 제공하는 비교자 생성 메서드를 사용합시다.
Comparable 사용 예제
public record Member( String name, int age ) implements Comparable<Member> { @Override public int compareTo(@NotNull Member m) { int result = Integer.compare(age, m.age); if(result == 0) { return name.compareTo(m.name); } return result; } }
public class ComparableExample { public static void main(String[] args) { List<Member> members = Lists.newArrayList(new Member("jini", 33), new Member("lily", 28), new Member("sol", 39), new Member("coco", 28)); Collections.sort(members); System.out.println(members); } }
[Member[name=coco, age=28], Member[name=lily, age=28], Member[name=jini, age=33], Member[name=sol, age=39]]
Comparator 사용 예
public record Student( String name, int age ) { }
public class ComparatorExample { public static void main(String[] args) { List<Student> students = Lists.newArrayList(new Student("jini", 33), new Student("lily", 28), new Student("sol", 39), new Student("coco", 28)); Collections.sort(students, COMPARATOR); System.out.println(students); } static final Comparator<Student> COMPARATOR = Comparator .comparingInt((Student s) -> s.age()) .thenComparing(s -> s.name()); }
[Student[name=coco, age=28], Student[name=lily, age=28], Student[name=jini, age=33], Student[name=sol, age=39]]
'Java > Effective Java' 카테고리의 다른 글
[Effective Java] Item17. 불변클래스를 이용하여 변경가능성을 최소화 하라 (0) | 2024.03.16 |
---|---|
[Effective Java] Item 15. 상수로 사용하고자하는 필드값이 불변객체인지 고려해야한다 (0) | 2024.03.16 |
[Effective Java] Item 10~11. equals는 일반 규약을 지켜서 재정의하라 (0) | 2024.03.10 |
Item 9. close 처리해야하는 resource는 try-with-resource를 이용하자 (0) | 2019.03.12 |
Item 6. 불필요한 객체 생성을 피하자 (0) | 2019.03.12 |