Skip to content

Latest commit

Β 

History

History
364 lines (260 loc) Β· 18.8 KB

item-14-comparable.md

File metadata and controls

364 lines (260 loc) Β· 18.8 KB

item 14 : Comparable 을 κ΅¬ν˜„ν• μ§€ κ³ λ €ν•˜λΌ

1. compareTo

ConpateToλž€?

{% hint style="info" %} Comparable μΈν„°νŽ˜μ΄μŠ€μ˜ μœ μΌλ¬΄μ΄ν•œ λ©”μ„œλ“œλ‘œ λ‹¨μˆœ λ™μΉ˜μ„± 비ꡐ에 더해 μˆœμ„œκΉŒμ§€ 비ꡐ할 수 있으며, μ œλ„€λ¦­ν•˜λ‹€.1 {% endhint %}

  • 3μž₯의 λ‹€λ₯Έ λ©”μ„œλ“œλ“€κ³Ό 달리 compareToλŠ” Object의 λ©”μ„œλ“œκ°€ μ•„λ‹ˆλ‹€.
  • 성격은 2가지λ₯Ό μ œμ™Έν•˜λ©΄, Object equals와 κ°™μŒ
  • compareTo λ₯Ό κ΅¬ν˜„ν–ˆλ‹€λŠ” 것은, μˆœμ„œκ°€ μ‘΄μž¬ν•˜λ‹€λŠ” 것이고, Arrays.sort λ₯Ό ν™œμš©ν•œ 정렬이 κ°€λŠ₯ν•˜λ‹€λŠ” 것
  • 보톡은 sqlμ—μ„œ order by둜 ν•œλ‹€λŠ” 것
public class WordList {
    public static void main(String[] args) {
        Set<String> s = new TreeSet ();
        Collections.addAll(s, args); 
        System.out.println(s);
    } 
}

사싀상 μžλ°” ν”Œλž«νΌ 라이브러리의 λͺ¨λ“  κ°’ ν΄λž˜μŠ€μ™€ μ—΄κ±° νƒ€μž…(μ•„μ΄ν…œ 34)이 Comparable을 κ΅¬ν˜„ν–ˆλ‹€. μ•ŒνŒŒλ²³, 숫자, μ—°λŒ€ 같이 μˆœμ„œκ°€ λͺ…ν™•ν•œ κ°’ 클래슀λ₯Ό μž‘μ„±ν•œλ‹€λ©΄ λ°˜λ“œμ‹œ Comparable μΈν„°νŽ˜μ΄μŠ€λ₯Ό κ΅¬ν˜„ν•˜μž.

2. CompareTo μΌλ°˜κ·œμ•½

public interface Comparable<T> { 
    int compareTo(T t);
}

ν•œ 눈의 정리 πŸ”₯

{% hint style="info" %} compareToκ°€ equals와 일관성을 μœ μ§€ν•˜λŠ” 것이 ꢌμž₯λ˜μ§€λ§Œ, μ΄λŠ” ν•„μˆ˜λŠ” μ•„λ‹ˆλ‹€. λŒ€μΉ­μ„±κ³Ό 좔이성은 ν•„μˆ˜μ΄λ‹€. ν•˜μ§€λ§Œλ§Œμ•½ compareTo와 equalsκ°€ μΌκ΄€λ˜μ§€ μ•ŠμœΌλ©΄ TreeSet 같은 μ •λ ¬λœ μ»¬λ ‰μ…˜μ—μ„œ μ˜ˆμƒμΉ˜ λͺ»ν•œ λ™μž‘μ΄ λ°œμƒν•  수 μžˆλ‹€. {% endhint %}

  1. λŒ€μΉ­μ„±: x.compareTo(y)κ°€ 음수면, y.compareTo(x)λŠ” μ–‘μˆ˜μ—¬μ•Ό ν•˜κ³ , x.compareTo(y)κ°€ 0이면 y.compareTo(x)도 0이어야 ν•œλ‹€.
  2. 좔이성: x.compareTo(y)κ°€ μ–‘μˆ˜μ΄κ³ , y.compareTo(z)κ°€ μ–‘μˆ˜λΌλ©΄, x.compareTo(z)도 μ–‘μˆ˜μ—¬μ•Ό ν•œλ‹€.
  3. 일관성: x.compareTo(y)κ°€ 0이면, x.compareTo(z)와 y.compareTo(z)λŠ” 같은 값을 κ°€μ Έμ•Ό ν•œλ‹€.

뢀가적인 λ‚΄μš© ⚑

λͺ¨λ“  객체에 λŒ€ν•΄ μ „μ—­ λ™μΉ˜κ΄€κ³„λ₯Ό λΆ€μ—¬ν•˜λŠ” equals λ©”μ„œλ“œμ™€ 달리, compareToλŠ” νƒ€μž…μ΄ λ‹€λ₯Έ 객체λ₯Ό μ‹ κ²½ 쓰지 μ•Šμ•„λ„ λœλ‹€.

νƒ€μž…μ΄ λ‹€λ₯Έ 객체가 주어지면 κ°„λ‹¨νžˆ ClassCastException을 λ˜μ Έλ„ λœλ‹€. compareTo κ·œμ•½μ„ 지킀지 λͺ»ν•˜λ©΄ 비ꡐλ₯Ό ν™œμš©ν•˜λŠ” ν΄λž˜μŠ€μ™€ μ–΄μšΈλ¦¬μ§€ λͺ»ν•œλ‹€.

compareTo λ©”μ„œλ“œμ˜ κ΅¬ν˜„κ³Ό equalsμ™€μ˜ 일관성 μœ μ§€μ˜ μ€‘μš”μ„±

{% hint style="info" %} compareTo λ©”μ„œλ“œμ˜ λ§ˆμ§€λ§‰ κ·œμ•½μ€ ν•„μˆ˜ 사항은 μ•„λ‹ˆμ§€λ§Œ, λ°˜λ“œμ‹œ μ§€ν‚€λŠ” 것이 μ’‹λ‹€. 이 κ·œμ•½μ€ κ°„λ‹¨νžˆ 말해, compareTo λ©”μ„œλ“œλ₯Ό 톡해 μˆ˜ν–‰ν•œ λ™μΉ˜μ„± ν…ŒμŠ€νŠΈμ˜ κ²°κ³Όκ°€ equals λ©”μ„œλ“œμ˜ 결과와 μΌμΉ˜ν•΄μ•Ό ν•œλ‹€λŠ” 것이닀. 이 κ·œμ•½μ„ 잘 지킀면 compareTo에 λ”°λ₯Έ μ •λ ¬ μˆœμ„œμ™€ equals의 κ²°κ³Όκ°€ μΌκ΄€λ˜κ²Œ λœλ‹€. {% endhint %}

κ·ΈλŸ¬λ‚˜ compareTo의 μˆœμ„œμ™€ equals의 κ²°κ³Όκ°€ μΌμΉ˜ν•˜μ§€ μ•ŠλŠ” ν΄λž˜μŠ€λ„ μ—¬μ „νžˆ λ™μž‘μ€ ν•œλ‹€. λ‹€λ§Œ, μ΄λŸ¬ν•œ 클래슀λ₯Ό μ •λ ¬λœ μ»¬λ ‰μ…˜(예: TreeSet, TreeMap)에 λ„£μœΌλ©΄ ν•΄λ‹Ή μ»¬λ ‰μ…˜μ΄ κ΅¬ν˜„ν•œ μΈν„°νŽ˜μ΄μŠ€(Collection, Set, Map)의 λ™μž‘κ³Ό μ—‡λ°•μžκ°€ λ°œμƒν•  수 μžˆλ‹€. μ΄λŠ” 이 μΈν„°νŽ˜μ΄μŠ€λ“€μ΄ equals λ©”μ„œλ“œμ˜ κ·œμ•½μ„ λ”°λ₯΄λ„둝 μ •μ˜λ˜μ–΄ μžˆμ§€λ§Œ, μ •λ ¬λœ μ»¬λ ‰μ…˜μ€ λ™μΉ˜μ„± 비ꡐ μ‹œ equals λŒ€μ‹  compareToλ₯Ό μ‚¬μš©ν•˜κΈ° λ•Œλ¬Έμ΄λ‹€.

ꢌμž₯ 사항:

  • κ°€λŠ₯ν•˜λ‹€λ©΄ x.equals(y)κ°€ true일 λ•Œ x.compareTo(y)λŠ” λ°˜λ“œμ‹œ 0을 λ°˜ν™˜ν•˜λ„λ‘ κ΅¬ν˜„ν•΄μ•Ό ν•œλ‹€.
  • λ°˜λŒ€λ‘œ x.compareTo(y)κ°€ 0일 λ•Œ x.equals(y)κ°€ trueκ°€ λ˜λ„λ‘ κ΅¬ν˜„ν•˜λ©΄ λ”μš± μ’‹λ‹€.

BigDecimal 클래슀의 μ˜ˆμ‹œ

compareTo와 equalsκ°€ μΌκ΄€λ˜μ§€ μ•ŠλŠ” 클래슀둜 BigDecimal을 예둜 λ“€ 수 μžˆλ‹€.

{% hint style="info" %} BigDecimal ν΄λž˜μŠ€μ—μ„œ equalsλŠ” 정밀도(precision)κΉŒμ§€ κ³ λ €ν•˜μ—¬ λΉ„κ΅ν•œλ‹€.

  • 예λ₯Ό λ“€μ–΄, new BigDecimal("1.0")κ³Ό new BigDecimal("1.00")은 equals둜 λΉ„κ΅ν•˜λ©΄ λ‹€λ₯Έ 객체둜 κ°„μ£Ό
  • ν•˜μ§€λ§Œ compareToλŠ” μˆ˜ν•™μ μΈ κ°’λ§Œμ„ λΉ„κ΅ν•˜λ―€λ‘œ, 두 객체λ₯Ό λ™μΌν•œ κ°’μœΌλ‘œ κ°„μ£Ό
  • 이둜 인해 HashSetκ³Ό TreeSetμ—μ„œ μ›μ†Œμ˜ κ°œμˆ˜κ°€ λ‹¬λΌμ§€λŠ” λ¬Έμ œκ°€ λ°œμƒν•œλ‹€. {% endhint %}
import java.math.BigDecimal;
import java.util.HashSet;
import java.util.TreeSet;

public class BigDecimalExample {
    public static void main(String[] args) {
        // HashSet 예제
        HashSet<BigDecimal> hashSet = new HashSet<>();
        hashSet.add(new BigDecimal("1.0"));
        hashSet.add(new BigDecimal("1.00"));
        System.out.println("HashSet 크기: " + hashSet.size()); // 좜λ ₯: 2

        // TreeSet 예제
        TreeSet<BigDecimal> treeSet = new TreeSet<>();
        treeSet.add(new BigDecimal("1.0"));
        treeSet.add(new BigDecimal("1.00"));
        System.out.println("TreeSet 크기: " + treeSet.size()); // 좜λ ₯: 1
    }
}

μ„€λͺ…:

  • HashSet에 new BigDecimal("1.0")κ³Ό new BigDecimal("1.00")을 μΆ”κ°€ν•˜λ©΄, equals λ©”μ„œλ“œλ‘œ λΉ„κ΅ν•˜μ—¬ 두 κ°μ²΄λŠ” λ‹€λ₯΄λ‹€κ³  νŒλ‹¨ν•˜λ―€λ‘œ HashSet의 μ›μ†ŒλŠ” 2κ°œκ°€ λœλ‹€.
  • λ°˜λ©΄μ— TreeSet은 compareTo λ©”μ„œλ“œλ‘œ λΉ„κ΅ν•˜μ—¬ 두 객체λ₯Ό κ°™λ‹€κ³  νŒλ‹¨ν•˜λ―€λ‘œ TreeSet의 μ›μ†ŒλŠ” 1κ°œκ°€ λœλ‹€.
  • 이둜 인해 HashSetκ³Ό TreeSetμ—μ„œ 같은 BigDecimal 객체λ₯Ό μ‚¬μš©ν•˜λ”λΌλ„ μ›μ†Œμ˜ κ°œμˆ˜κ°€ λ‹¬λΌμ§€λŠ” λ¬Έμ œκ°€ λ°œμƒν•œλ‹€.

πŸ€” 음.. μ΄κ±°λŠ” HashSetκ³Ό TreeSet 의 자료ꡬ쑰의 문제 아냐?

λ‹΅λ³€ : μ΄λŸ¬ν•œ ν˜„μƒμ€ BigDecimal 클래슀의 섀계와 μ»¬λ ‰μ…˜ ν”„λ ˆμž„μ›Œν¬μ˜ λ™μž‘ λ°©μ‹μ˜ 차이둜 인해 λ°œμƒν•˜λŠ” κ²ƒμž…λ‹ˆλ‹€. 일반적으둜 equals()와 compareTo() λ©”μ„œλ“œλŠ” μΌκ΄€λ˜κ²Œ λ™μž‘ν•˜λ„λ‘ κ΅¬ν˜„ν•˜λŠ” 것이 ꢌμž₯λ©λ‹ˆλ‹€. 즉, equals()둜 κ°™λ‹€κ³  νŒλ‹¨λ˜λŠ” κ°μ²΄λŠ” compareTo()둜 λΉ„κ΅ν–ˆμ„ λ•Œ 0을 λ°˜ν™˜ν•΄μ•Ό ν•©λ‹ˆλ‹€.

ν•˜μ§€λ§Œ BigDecimal ν΄λž˜μŠ€λŠ” 정밀도(precision)λ₯Ό μ€‘μš”μ‹œν•˜κΈ° λ•Œλ¬Έμ— equals() λ©”μ„œλ“œμ—μ„œ μŠ€μΌ€μΌκΉŒμ§€ κ³ λ €ν•˜λ„λ‘ μ„€κ³„λ˜μ—ˆμŠ΅λ‹ˆλ‹€. λ°˜λ©΄μ— 수치적인 비ꡐλ₯Ό μœ„ν•œ compareTo()λŠ” μŠ€μΌ€μΌμ„ λ¬΄μ‹œν•˜κ³  κ°’λ§Œ λΉ„κ΅ν•˜λ„λ‘ λ˜μ–΄ μžˆμŠ΅λ‹ˆλ‹€.

λ”°λΌμ„œ μ΄λŠ” 클래슀의 섀계 μ˜λ„μ— λ”°λ₯Έ 결과이며, μ»¬λ ‰μ…˜ ν”„λ ˆμž„μ›Œν¬μ˜ λ™μž‘κ³Ό μΆ©λŒν•  수 μžˆλŠ” λΆ€λΆ„μž…λ‹ˆλ‹€. μ΄λŸ¬ν•œ 차이둜 인해 λ°œμƒν•˜λŠ” λ¬Έμ œλŠ” κ°œλ°œμžκ°€ μΈμ§€ν•˜κ³  쑰심해야 ν•  뢀뢄이지, Java μ–Έμ–΄λ‚˜ μ»¬λ ‰μ…˜ ν”„λ ˆμž„μ›Œν¬μ˜ ꡬ쑰적인 결함이라고 λ³΄κΈ°λŠ” μ–΄λ ΅μŠ΅λ‹ˆλ‹€.

λ”°λΌμ„œ, ꡬ쑰적인 λ¬Έμ œλΌκΈ°λ³΄λ‹€λŠ” ν•΄λ‹Ή ν΄λž˜μŠ€μ™€ μ»¬λ ‰μ…˜ μ‚¬μš© μ‹œ μ£Όμ˜ν•΄μ•Ό ν•  μ‚¬ν•­μœΌλ‘œ λ³΄λŠ” 것이 λ§žμŠ΅λ‹ˆλ‹€

πŸ€” ν•˜μ§€λ§Œ μœ„μ˜ μ½”λ“œλŠ” compareToλ©”μ„œλ“œκ°€ μ•„λ‹ˆλΌ sizeλΌλŠ” λ©”μ„œλ“œλ₯Ό μ“΄κ±° μ•„λ‹Œκ°€?

  • 예제 μ½”λ“œμ—μ„œ size() λ©”μ„œλ“œλ₯Ό μ‚¬μš©ν•œ 것은 집합에 μ‹€μ œλ‘œ λͺ‡ 개의 μ›μ†Œκ°€ μ €μž₯λ˜μ—ˆλŠ”μ§€ ν™•μΈν•˜κΈ° μœ„ν•œ κ²ƒμž…λ‹ˆλ‹€.
  • μ›μ†Œμ˜ κ°œμˆ˜κ°€ λ‹¬λΌμ§€λŠ” μ΄μœ λŠ” HashSetκ³Ό TreeSet이 μ›μ†Œμ˜ 동일성을 νŒλ‹¨ν•˜λŠ” 기쀀이 λ‹€λ₯΄κΈ° λ•Œλ¬Έμž…λ‹ˆλ‹€.
    • HashSet은 equals()와 hashCode()λ₯Ό μ‚¬μš©ν•˜κ³ ,
    • TreeSet은 compareTo()λ₯Ό μ‚¬μš©ν•©λ‹ˆλ‹€.
    • BigDecimal 클래슀의 equals()와 compareTo() λ©”μ„œλ“œκ°€ μΌκ΄€λ˜μ§€ μ•Šκ²Œ λ™μž‘ν•˜κΈ° λ•Œλ¬Έμ— 이런 차이가 λ°œμƒν•©λ‹ˆλ‹€.

{% hint style="info" %} 즉, size() λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœν•˜κΈ° 전에 μ›μ†Œλ₯Ό μΆ”κ°€ν•˜λŠ” κ³Όμ •μ—μ„œ compareTo()와 equals() λ©”μ„œλ“œκ°€ μ–΄λ–»κ²Œ λ™μž‘ν•˜λŠ”μ§€κ°€ μ§‘ν•©μ˜ μ›μ†Œ κ°œμˆ˜μ— 영ν–₯을 미치게 λ©λ‹ˆλ‹€. {% endhint %}

  1. HashSet의 λ™μž‘ 원리
  • HashSet에 μ›μ†Œλ₯Ό μΆ”κ°€ν•  λ•Œ, μ›μ†Œμ˜ hashCode() 값을 μ‚¬μš©ν•˜μ—¬ 버킷을 κ²°μ •ν•©λ‹ˆλ‹€.
  • 이미 같은 hashCode()λ₯Ό 가진 μ›μ†Œκ°€ μžˆλŠ” 경우, equals() λ©”μ„œλ“œλ₯Ό μ‚¬μš©ν•˜μ—¬ 두 μ›μ†Œκ°€ λ™μΌν•œμ§€ λΉ„κ΅ν•©λ‹ˆλ‹€.
  • equals() λ©”μ„œλ“œκ°€ falseλ₯Ό λ°˜ν™˜ν•˜λ©΄, ν•΄λ‹Ή μ›μ†ŒλŠ” 집합에 μƒˆλ‘œμš΄ μ›μ†Œλ‘œ μΆ”κ°€λ©λ‹ˆλ‹€.

2. TreeSet의 λ™μž‘ 원리

  • TreeSet은 이진 탐색 트리λ₯Ό 기반으둜 κ΅¬ν˜„λ˜μ–΄ 있으며, μ›μ†Œλ₯Ό μ •λ ¬λœ μˆœμ„œλ‘œ μœ μ§€ν•©λ‹ˆλ‹€.
  • μ›μ†Œλ₯Ό μΆ”κ°€ν•  λ•Œ, compareTo() λ©”μ„œλ“œλ‚˜ 제곡된 Comparatorλ₯Ό μ‚¬μš©ν•˜μ—¬ μ›μ†Œμ˜ μˆœμ„œμ™€ 동일성을 νŒλ‹¨ν•©λ‹ˆλ‹€.
  • compareTo() λ©”μ„œλ“œκ°€ 0을 λ°˜ν™˜ν•˜λ©΄, 두 μ›μ†ŒλŠ” λ™μΌν•œ κ²ƒμœΌλ‘œ κ°„μ£Όλ˜μ–΄ μƒˆλ‘œμš΄ μ›μ†Œλ‘œ μΆ”κ°€λ˜μ§€ μ•ŠλŠ”λ‹€.
  1. ν•΄κ²° 방법 🍁
  • compareTo()와 equals()의 κ΅¬ν˜„μ„ μΌκ΄€λ˜κ²Œ μˆ˜μ •ν•œλ‹€.
    • ν•˜μ§€λ§Œ BigDecimal ν΄λž˜μŠ€λŠ” Java ν‘œμ€€ 라이브러리의 ν΄λž˜μŠ€μ΄λ―€λ‘œ μš°λ¦¬κ°€ μˆ˜μ •ν•  수 μ—†λ‹€.
  • μ»€μŠ€ν…€ Comparatorλ₯Ό μ‚¬μš©ν•˜μ—¬ TreeSet의 λ™μž‘μ„ μˆ˜μ •ν•œλ‹€.
    • μŠ€μΌ€μΌκΉŒμ§€ κ³ λ €ν•˜λ„λ‘ Comparatorλ₯Ό μ •μ˜ν•˜λ©΄ TreeSetμ—μ„œλ„ μ›μ†Œμ˜ κ°œμˆ˜κ°€ 2κ°œκ°€ 됨

compareTo λ©”μ„œλ“œλ₯Ό μ˜¬λ°”λ₯΄κ²Œ κ΅¬ν˜„ν•˜κ³ , equalsμ™€μ˜ 일관성을 μœ μ§€ν•˜λŠ” 방법을 이해할 수 μžˆλ‹€. μ΄λŠ” μ½”λ“œμ˜ μ‹ λ’°μ„±κ³Ό μœ μ§€λ³΄μˆ˜μ„±μ„ 높이고, μ»¬λ ‰μ…˜ ν”„λ ˆμž„μ›Œν¬λ₯Ό μ‚¬μš©ν•  λ•Œ λ°œμƒν•  수 μžˆλŠ” 였λ₯˜λ₯Ό μ˜ˆλ°©ν•˜λŠ” 데 μ€‘μš”

πŸ”₯ μ»¬λ ‰μ…˜ μ‚¬μš© μ‹œ μ£Όμ˜μ‚¬ν•­

  • μ»¬λ ‰μ…˜μ— μ›μ†Œλ₯Ό μΆ”κ°€ν•  λ•Œ, ν•΄λ‹Ή μ»¬λ ‰μ…˜μ΄ μ›μ†Œμ˜ 동일성을 μ–΄λ–€ κΈ°μ€€μœΌλ‘œ νŒλ‹¨ν•˜λŠ”μ§€ μ•Œμ•„μ•Ό ν•œλ‹€.
  • equals()와 compareTo() λ©”μ„œλ“œμ˜ κ΅¬ν˜„μ΄ μΌκ΄€λ˜μ§€ μ•ŠμœΌλ©΄ μ»¬λ ‰μ…˜μ—μ„œ 예기치 μ•Šμ€ λ™μž‘μ΄ λ°œμƒν•  수 μžˆλ‹€.

3. compareTo λ©”μ„œλ“œ μž‘μ„± μš”λ Ή

compareTo λ©”μ„œλ“œλ₯Ό μž‘μ„±ν•  λ•ŒλŠ” equals λ©”μ„œλ“œμ™€ λΉ„μŠ·ν•œ μš”λ Ήμ„ λ”°λ₯΄μ§€λ§Œ, λͺ‡ 가지 차이점을 μ£Όμ˜ν•΄μ•Ό ν•œλ‹€.

  1. νƒ€μž… 검사와 ν˜•λ³€ν™˜ λΆˆν•„μš”:
    • Comparable은 μ œλ„€λ¦­ μΈν„°νŽ˜μ΄μŠ€μ΄λ―€λ‘œ, compareTo λ©”μ„œλ“œμ˜ 인수 νƒ€μž…μ€ 컴파일 νƒ€μž„μ— 정해진닀.
    • 인수의 νƒ€μž…μ΄ 잘λͺ»λ˜λ©΄ 컴파일 μžμ²΄κ°€ λ˜μ§€ μ•ŠμœΌλ―€λ‘œ, λŸ°νƒ€μž„ νƒ€μž… κ²€μ‚¬λ‚˜ ν˜•λ³€ν™˜μ΄ ν•„μš” μ—†λ‹€.
  2. null 처리:
    • compareTo λ©”μ„œλ“œμ— null을 인수둜 λ„£μœΌλ©΄ NullPointerException을 λ˜μ§€λŠ” 것이 μΌλ°˜μ μ΄λ‹€.
    • μ‹€μ œλ‘œλ„ 인수(null)의 멀버에 μ ‘κ·Όν•˜λ €λŠ” μˆœκ°„ 이 μ˜ˆμ™Έκ°€ λ°œμƒν•œλ‹€.
  3. ν•„λ“œ 비ꡐ 방법:
    • compareTo λ©”μ„œλ“œλŠ” 각 ν•„λ“œκ°€ λ™μΉ˜μΈμ§€λ₯Ό λΉ„κ΅ν•˜λŠ” 것이 μ•„λ‹ˆλΌ, μˆœμ„œλ₯Ό λΉ„κ΅ν•œλ‹€.
    • κΈ°λ³Έ νƒ€μž… ν•„λ“œλŠ” <, > μ—°μ‚°μžλ₯Ό μ‚¬μš©ν•˜μ—¬ λΉ„κ΅ν•œλ‹€.
    • 객체 μ°Έμ‘° ν•„λ“œλŠ” ν•΄λ‹Ή 클래슀의 compareTo λ©”μ„œλ“œλ₯Ό μž¬κ·€μ μœΌλ‘œ ν˜ΈμΆœν•˜μ—¬ λΉ„κ΅ν•œλ‹€.
    • Comparable을 κ΅¬ν˜„ν•˜μ§€ μ•Šμ€ ν•„λ“œλ‚˜ ν‘œμ€€μ΄ μ•„λ‹Œ μˆœμ„œλ‘œ 비ꡐ해야 ν•˜λŠ” κ²½μš°μ—λŠ” Comparatorλ₯Ό μ‚¬μš©ν•œλ‹€.

4. compareTo λ©”μ„œλ“œ κ΅¬ν˜„κ³Ό Comparator ν™œμš©

{% hint style="info" %} μžλ°” 7μ΄ν›„λΆ€ν„°λŠ”compareTo λ©”μ„œλ“œμ—μ„œ 관계 μ—°μ‚°μž οΌœμ™€ > λ₯Ό μ‚¬μš©ν•˜λŠ” 이전 방식은 κ±°μΆ”μž₯슀럽고 였λ₯˜λ₯Ό μœ λ°œν•˜λ‹ˆ , μ΄μ œλŠ” μΆ”μ²œν•˜μ§€ μ•ŠλŠ”λ‹€. λ°•μ‹±λœ κΈ°λ³Έ νƒ€μž… ν΄λž˜μŠ€λ“€μ— μƒˆλ‘œ μΆ”κ°€λœ 정적 λ©”μ„œλ“œμΈ compareλ₯Ό μ΄μš©ν•˜λ©΄ λœλ‹€. {% endhint %}

1) μ—¬λŸ¬ ν•„λ“œλ₯Ό λΉ„κ΅ν•˜λŠ” compareTo λ©”μ„œλ“œ κ΅¬ν˜„

ν΄λž˜μŠ€μ— 핡심 ν•„λ“œκ°€ μ—¬λŸ¬ 개라면 μ–΄λŠ 것을 λ¨Όμ € λΉ„κ΅ν•˜λŠλƒκ°€ μ€‘μš”ν•΄μ§„λ‹€. κ°€μž₯ μ€‘μš”ν•œ ν•„λ“œλΆ€ν„° λΉ„κ΅ν•΄λ‚˜κ°€λŠ” 것이 μ’‹λ‹€.

  • 비ꡐ κ²°κ³Όκ°€ 0이 μ•„λ‹ˆλΌλ©΄, 즉 μˆœμ„œκ°€ κ²°μ •λ˜λ©΄ κ·Έ κ²°κ³Όλ₯Ό 곧μž₯ λ°˜ν™˜ν•œλ‹€.
  • κ°€μž₯ μ€‘μš”ν•œ ν•„λ“œκ°€ κ°™λ‹€λ©΄, κ·Έλ‹€μŒμœΌλ‘œ μ€‘μš”ν•œ ν•„λ“œλ₯Ό λΉ„κ΅ν•΄λ‚˜κ°„λ‹€.

μ˜ˆμ‹œ: PhoneNumber 클래슀의 compareTo λ©”μ„œλ“œ

public int compareTo(PhoneNumber pn) {
    int result = Short.compare(areaCode, pn.areaCode); // κ°€μž₯ μ€‘μš”ν•œ ν•„λ“œ 비ꡐ
    if (result == 0) {
        result = Short.compare(prefix, pn.prefix); // 두 번째둜 μ€‘μš”ν•œ ν•„λ“œ 비ꡐ
        if (result == 0) {
            result = Short.compare(lineNum, pn.lineNum); // μ„Έ 번째둜 μ€‘μš”ν•œ ν•„λ“œ 비ꡐ
        }
    }
    return result;
  • short.compareλ₯Ό μ‚¬μš©ν•˜μ—¬ short νƒ€μž… ν•„λ“œλ₯Ό λΉ„κ΅ν•œλ‹€.
  • μ΄λ ‡κ²Œ ν•˜λ©΄ μ½”λ“œκ°€ 간결해지고, μ˜€λ²„ν”Œλ‘œμš° λ“±μ˜ 문제λ₯Ό 방지할 수 μžˆλ‹€.

2) Comparator 생성 λ©”μ„œλ“œλ₯Ό ν™œμš©ν•œ compareTo κ΅¬ν˜„

μžλ°” 8λΆ€ν„°λŠ” Comparator μΈν„°νŽ˜μ΄μŠ€μ— λΉ„κ΅μž 생성 λ©”μ„œλ“œλ“€μ΄ μΆ”κ°€λ˜μ–΄, λ©”μ„œλ“œ 연쇄 λ°©μ‹μœΌλ‘œ λΉ„κ΅μžλ₯Ό 생성할 수 μžˆλ‹€. 이λ₯Ό ν™œμš©ν•˜λ©΄ compareTo λ©”μ„œλ“œλ₯Ό 더 κ°„κ²°ν•˜κ²Œ κ΅¬ν˜„ν•  수 μžˆλ‹€.

μ˜ˆμ‹œ: PhoneNumber 클래슀의 compareTo λ©”μ„œλ“œ

import static java.util.Comparator.comparingInt;

private static final Comparator<PhoneNumber> COMPARATOR =
    comparingInt((PhoneNumber pn) -> pn.areaCode)
        .thenComparingInt(pn -> pn.prefix)
        .thenComparingInt(pn -> pn.lineNum);

@Override
public int compareTo(PhoneNumber pn) {
    return COMPARATOR.compare(this, pn);
}
  • comparingInt λ©”μ„œλ“œλŠ” ν‚€ μΆ”μΆœ ν•¨μˆ˜λ₯Ό λ°›μ•„ κ·Έ ν‚€λ₯Ό κΈ°μ€€μœΌλ‘œ λΉ„κ΅ν•˜λŠ” Comparatorλ₯Ό 생성
  • thenComparingInt λ©”μ„œλ“œλ₯Ό μ‚¬μš©ν•˜μ—¬ 좔가적인 ν•„λ“œλ₯Ό 순차적으둜 λΉ„κ΅ν•œλ‹€.

μ£Όμ˜μ‚¬ν•­:

  • 이 방식은 μ½”λ“œμ˜ 간결함을 μ œκ³΅ν•˜μ§€λ§Œ, μ•½κ°„μ˜ μ„±λŠ₯ μ €ν•˜κ°€ μžˆμ„ 수 μžˆλ‹€. ν…ŒμŠ€νŠΈ κ²°κ³Ό μ•½ 10% 정도 느렀질 수 μžˆλ‹€.
  • λ”°λΌμ„œ μ„±λŠ₯이 μ€‘μš”ν•œ μƒν™©μ—μ„œλŠ” 전톡적인 λ°©μ‹μœΌλ‘œ κ΅¬ν˜„ν•˜λŠ” 것이 쒋을 수 μžˆμŠ΅λ‹ˆλ‹€.
  • 전톡방식
public class PhoneNumber implements Comparable<PhoneNumber> {
    private final short areaCode;
    private final short prefix;
    private final short lineNum;

    // μƒμ„±μž 및 기타 λ©”μ„œλ“œ μƒλž΅

    @Override
    public int compareTo(PhoneNumber pn) {
        int result = Short.compare(areaCode, pn.areaCode);
        if (result == 0) {
            result = Short.compare(prefix, pn.prefix);
            if (result == 0) {
                result = Short.compare(lineNum, pn.lineNum);
            }
        }
        return result;
    }
}

3) Comparator의 λ‹€μ–‘ν•œ λ©”μ„œλ“œ ν™œμš©

ComparatorλŠ” λ‹€μ–‘ν•œ 보쑰 생성 λ©”μ„œλ“œλ“€μ„ μ œκ³΅ν•œλ‹€.

  • 숫자 νƒ€μž… ν•„λ“œλ₯Ό λΉ„κ΅ν•˜κΈ° μœ„ν•œ λ©”μ„œλ“œ:
    • comparingInt, comparingLong, comparingDouble
    • thenComparingInt, thenComparingLong, thenComparingDouble
  • 객체 μ°Έμ‘° νƒ€μž… ν•„λ“œλ₯Ό λΉ„κ΅ν•˜κΈ° μœ„ν•œ λ©”μ„œλ“œ:
    • comparing λ©”μ„œλ“œ: ν‚€ μΆ”μΆœμžλ₯Ό λ°›μ•„ ν‚€μ˜ μžμ—° μˆœμ„œλ‚˜ μ§€μ •ν•œ Comparator둜 비ꡐ
    • thenComparing λ©”μ„œλ“œ: 좔가적인 비ꡐ 기쀀을 지정

μ˜ˆμ‹œ: 객체 μ°Έμ‘° ν•„λ“œ 비ꡐ

javaμ½”λ“œ 볡사Comparator<Person> personComparator = Comparator
    .comparing(Person::getLastName)
    .thenComparing(Person::getFirstName)
    .thenComparingInt(Person::getAge);
  • Person 클래슀의 lastName, firstName, age ν•„λ“œλ₯Ό 순차적으둜 비ꡐ

4) 잘λͺ»λœ compareTo κ΅¬ν˜„ 방식 ν”Όν•˜κΈ°

가끔 κ°’μ˜ 차이λ₯Ό λ°˜ν™˜ν•˜μ—¬ λΉ„κ΅ν•˜λŠ” compareTo λ©”μ„œλ“œλ₯Ό λ³Ό 수 μžˆλ‹€.

// 잘λͺ»λœ κ΅¬ν˜„ - μ‚¬μš©ν•˜μ§€ 말 것!
public int compareTo(PhoneNumber pn) {
    return areaCode - pn.areaCode;
}
  • 이 방식은 μ˜€λ²„ν”Œλ‘œμš°λ‚˜ μ–Έλ”ν”Œλ‘œμš°κ°€ λ°œμƒν•  수 μžˆμ–΄ μ‹ λ’°ν•  수 μ—†λ‹€.
  • λ˜ν•œ, λΆ€λ™μ†Œμˆ˜μ  νƒ€μž…μ—μ„œλŠ” 정밀도 손싀이 λ°œμƒν•  수 μžˆλ‹€.

μ˜¬λ°”λ₯Έ κ΅¬ν˜„ 방식:

public int compareTo(PhoneNumber pn) {
    int result = Short.compare(areaCode, pn.areaCode);
    if (result == 0) {
        result = Short.compare(prefix, pn.prefix);
        if (result == 0) {
            result = Short.compare(lineNum, pn.lineNum);
        }
    }
    return result;
}
  • 정적 compare λ©”μ„œλ“œλ₯Ό μ‚¬μš©
  • λ˜λŠ” Comparator 생성 λ©”μ„œλ“œλ₯Ό ν™œμš©ν•œλ‹€.

5) μ˜¬λ°”λ₯Έ λΉ„κ΅μž

정적 compare λ©”μ„œλ“œ ν™œμš©:

static Comparator<Object> hashCodeOrder = new Comparator<Object>() {
    public int compare(Object o1, Object o2) {
        return Integer.compare(o1.hashCode(), o2.hashCode());
    }
};
  • Integer.compareλ₯Ό μ‚¬μš©ν•˜μ—¬ μ˜€λ²„ν”Œλ‘œμš° 없이 μ•ˆμ „ν•˜κ²Œ λΉ„κ΅ν•œλ‹€.

2. λΉ„κ΅μž 생성 λ©”μ„œλ“œ ν™œμš©:

static Comparator<Object> hashCodeOrder =
    Comparator.comparingInt(o -> o.hashCode());
  • Comparator.comparingIntλ₯Ό μ‚¬μš©ν•˜μ—¬ λ”μš± κ°„κ²°ν•˜κ²Œ κ΅¬ν˜„ν•œλ‹€.

유의 사항

  • compareTo λ©”μ„œλ“œμ—μ„œ ν•„λ“œλ₯Ό 비ꡐ할 λ•ŒλŠ”:
    • κΈ°λ³Έ νƒ€μž… ν•„λ“œλŠ” ν•΄λ‹Ή λ°•μ‹± 클래슀의 정적 compare λ©”μ„œλ“œλ₯Ό μ‚¬μš©
    • 객체 μ°Έμ‘° ν•„λ“œλŠ” ν•΄λ‹Ή ν•„λ“œμ˜ compareTo λ©”μ„œλ“œλ₯Ό μž¬κ·€μ μœΌλ‘œ ν˜ΈμΆœν•œλ‹€.
    • Comparable을 κ΅¬ν˜„ν•˜μ§€ μ•Šμ€ ν•„λ“œλŠ” μ μ ˆν•œ Comparatorλ₯Ό μ‚¬μš©ν•œλ‹€.
  • ν•„λ“œμ˜ 비ꡐ μˆœμ„œλŠ” μ€‘μš”λ„μ— 따라 μ •ν•˜κΈ°
    • κ°€μž₯ μ€‘μš”ν•œ ν•„λ“œλΆ€ν„° λΉ„κ΅ν•˜μ—¬ μˆœμ„œκ°€ κ²°μ •λ˜λ©΄ μ¦‰μ‹œ λ°˜ν™˜
  • Comparator 생성 λ©”μ„œλ“œλ₯Ό μ‚¬μš©ν•˜λ©΄ μ½”λ“œκ°€ 간결해짐
    • κ·ΈλŸ¬λ‚˜ μ„±λŠ₯ μ €ν•˜κ°€ μžˆμ„ 수 μžˆμœΌλ―€λ‘œ 상황에 맞게 선택
  • κ°’μ˜ 차이λ₯Ό λ°˜ν™˜ν•˜λŠ” 방식은 ν”Όν•΄μ•Ό ν•œλ‹€.
    • μ˜€λ²„ν”Œλ‘œμš°, μ–Έλ”ν”Œλ‘œμš° λ“±μ˜ 문제λ₯Ό μΌμœΌν‚¬ 수 μžˆλ‹€.
  • compareTo λ©”μ„œλ“œ κ΅¬ν˜„ μ‹œ:
    • 정적 λΉ„κ΅μž 생성 λ©”μ„œλ“œλ₯Ό ν™œμš©ν•˜μ—¬ κ°„κ²°ν•˜κ³  λͺ…ν™•ν•œ μ½”λ“œλ₯Ό μž‘μ„±ν•œλ‹€.
    • ν•„λ“œμ˜ μ€‘μš”λ„ μˆœμ„œμ— 따라 비ꡐλ₯Ό μ§„ν–‰ν•œλ‹€.
    • νƒ€μž… μΆ”λ‘ μ˜ ν•œκ³„λ‘œ 인해 λžŒλ‹€ ν‘œν˜„μ‹μ—μ„œ νƒ€μž…μ„ λͺ…μ‹œν•΄μ•Ό ν•  λ•Œκ°€ μžˆμœΌλ‹ˆ μ£Όμ˜ν•΄μ•Ό ν•œλ‹€.

✨ 결둠

  1. μˆœμ„œλ₯Ό κ³ λ €ν•΄μ•Ό ν•˜λŠ” κ°’ 클래슀λ₯Ό μž‘μ„±ν•œλ‹€λ©΄ κΌ­ Comparable μΈν„°νŽ˜μ΄μŠ€λ₯Ό κ΅¬ν˜„ν•˜μ—¬, κ·Έ μΈμŠ€ν„΄μŠ€λ“€μ„ μ‰½κ²Œ μ •λ ¬ν•˜κ³ , κ²€μƒ‰ν•˜κ³ , 비ꡐ κΈ°λŠ₯을 μ œκ³΅ν•˜λŠ” μ»¬λ ‰μ…˜κ³Ό μ–΄μš°λŸ¬ 지도둝 ν•΄μ•Ό ν•œλ‹€.
  2. compareTo λ©”μ„œλ“œμ—μ„œ ν•„λ“œμ˜ 값을 비ꡐ할 λ•Œ <와 > μ—°μ‚°μžλŠ” 쓰지 말아야 ν•œλ‹€.
  • κ·Έ λŒ€μ‹  λ°•μ‹±λœ κΈ°λ³Έ νƒ€μž… ν΄λž˜μŠ€κ°€ μ œκ³΅ν•˜λŠ” 정적 compare λ©”μ„œλ“œλ‚˜ Comparator μΈν„°νŽ˜μ΄μŠ€κ°€ μ œκ³΅ν•˜λŠ” λΉ„κ΅μž 생성 λ©”μ„œλ“œλ₯Ό μ‚¬μš©ν•˜μž.

Footnotes

  1. 비ꡐ할 λ•Œ νƒ€μž…μ— 관계없이 μ‚¬μš©ν•  수 μžˆμŒμ„ μ˜λ―Έν•©λ‹ˆλ‹€. 즉, λ‹€μ–‘ν•œ νƒ€μž…μ— 적용 κ°€λŠ₯ν•˜λ‹€λŠ” 의미 ↩

  2. String ν΄λž˜μŠ€λŠ” Comparable<String> μΈν„°νŽ˜μ΄μŠ€λ₯Ό κ΅¬ν˜„ν•˜κ³  있으며, 이둜 인해 compareTo λ©”μ„œλ“œλ₯Ό μ‚¬μš©ν•˜μ—¬ λ¬Έμžμ—΄μ„ 사전식(μ•ŒνŒŒλ²³ μˆœμ„œ)으둜 비ꡐ할 수 μžˆλ‹€. TreeSet은 λ‚΄λΆ€μ μœΌλ‘œ μ‚½μž…λœ μš”μ†Œλ“€μ„ μžλ™μœΌλ‘œ μ •λ ¬ν•˜λŠ” μžλ£Œκ΅¬μ‘°μ΄λ‹€. λ”°λΌμ„œ TreeSet에 String 객체듀을 μ‚½μž…ν•˜λ©΄ String의 compareTo λ©”μ„œλ“œλ₯Ό 기반으둜 μ‚¬μ „μˆœμœΌλ‘œ μ •λ ¬ ↩