Skip to content

Commit 6858775

Browse files
committed
Create 나희도_4장_14아이템.md
1 parent 5877638 commit 6858775

2 files changed

Lines changed: 182 additions & 2 deletions

File tree

02강/item11_equals를 재정의하려거든 hashCode도 재정의하라.md renamed to 03강/item11_equals를 재정의하려거든 hashCode도 재정의하라.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -297,5 +297,4 @@ AutoValue 프레임워크를 사용하면 `equals`와 `hashCode`를 자동으
297297

298298
<br/>
299299

300-
### 사실 요즘은 직접 만들기보다 IDE의 도움을 받아 만드는 것이 좋다.
301-
300+
### 사실 요즘은 직접 만들기보다 IDE의 도움을 받아 만드는 것이 좋다.
Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
## Comparable을 구현할지 고려하라
2+
3+
## 두줄 정리
4+
5+
- 순서가 있는 클래스를 작성한다면, `Comparable` 인터페이스를 구현하는 것이 좋다.
6+
7+
- `compareTo` 메서드를 구현할 때는 박싱 클래스에서 제공하는 `compare()`를 적극 활용하자.
8+
9+
<br/>
10+
11+
## `Comparable` 이란?
12+
13+
- `Comparable` 인터페이스는 객체를 정렬하는데 사용되는 메서드인 `compareTo`를 정의하고 있다.
14+
15+
- `Comparable` 인터페이스를 구현한 클래스는 반드시 `compareTo`를 정의해야 한다.
16+
17+
<br/>
18+
19+
## `Comparable` 인터페이스 특징?
20+
21+
- 자바에서 같은 타입의 인스턴스를 비교해야만 하는 클래스들은 모두 `Comparable` 인터페이스를 구현하고 있다.
22+
23+
- `Boolean` 타입을 제외한 래퍼 클래스와 알파벳, 연대같이 순서가 명확한 클래스들은 모두 정렬이 가능하다.
24+
- 기본 정렬 순서는 작은 값에서 큰 값으로 정렬되는 **오름차순**이다.
25+
26+
<br/>
27+
28+
## `Comparable` 구현의 장점은?
29+
30+
- `Comparable`을 구현한 객체의 배열은 쉽게 정렬 가능하다.
31+
32+
- ex) `Arrays.sort(a)`
33+
34+
- `Collection` 객체들에서도 정렬을 활용할 수 있다.
35+
36+
- `TreeSet` 자료구조 같은 경우, `Comparable`을 구현한 타입만 제너릭으로 받을 수 있다.
37+
38+
- `String` 타입을 넣는 경우, 들어간 모든 문자열을 알파벳순으로 출력 가능하다.
39+
40+
<br/>
41+
42+
natrual order만 정의해줄 뿐인데, 부가 효과가 많다.
43+
44+
반대로 구현하지 않았을 경우, 부가 효과를 못 누린다는 뜻이다.
45+
46+
<br/>
47+
48+
## `Comparable` 인터페이스의 `compareTo` 메서드
49+
50+
`compareTo`는 해당 객체와 전달된 객체의 순서를 비교한다.
51+
52+
- `compareTo`는 `Object`의 `euqals`와 두가지 차이점이 있다.
53+
54+
- `compareTo`는 `equals`와 달리 단순 동치성에 더해 순서까지 비교할 수 있으며, 제네릭하다.
55+
56+
- `Comparable`을 구현했다는 것은 그 클래스의 인스턴스에 자연적인 순서가 있음을 뜻한다.
57+
58+
- 예를 들어, `Comparable`을 구현한 객체들의 배열은 `Arrays.sort(a)`로 쉽게 정렬이 가능하다.
59+
60+
<br/>
61+
62+
## `compareTo` 메서드 일반규약
63+
64+
먼저 짚고 넘어갈 `compareTo`의 반환값에 대해 살펴보면
65+
66+
기준이 되는 객체를 x, 비교를 하는 객체를 y라 할 때
67+
68+
x 가 y보다 작은 경우 -1을, 같을 경우 0을, 클 경우 1을 반환한다.
69+
70+
결국 두 가지 차이를 빼고 `compareTo`는 기본적으로 equals와 비슷하다.
71+
72+
<br/>
73+
74+
- `compareTo`는 동치성 비교 뿐만 아니라 순서까지 비교할 수 있다
75+
- 또한, 제네릭하기 때문에 형변환에 대한 부담이 없다
76+
77+
따라서 `compareTo` 메서드의 일반 규약은 `equals`의 규약과 비슷하다  (아이템10)
78+
79+
<br/>
80+
81+
즉, 반사성/대칭성/추이성을 지켜야 한다
82+
83+
- 이 항목은 필수는 아니지만 꼭 지키는 게 좋다
84+
- 정렬된 컬렉션에서 동치성을 비교할 때 `equals` 대신 `compareTo`를 사용하기 때문에 안 지키면 이상하게 동작할 수 있음
85+
86+
87+
<br/>
88+
89+
## 구현은?
90+
91+
- `Comparable`은 타입을 인수로 받는 제네릭 인터페이스이므로 `compareTo`의 인수타입은 컴파일 시에 정해지기 때문에
92+
93+
입력 인수 확인이나 형변환을 할 필요가 없다.
94+
- 단순히 다른 타입이 온다면 `ClassCastException`을 발생시키면 된다. (대부분 그렇게 되어있다)
95+
- 다른 타입간의 비교도 허용하지만 공통 인터페이스를 기반으로 했다는 전제하에 가능하다.
96+
97+
<br/>
98+
99+
## `equals`와 `compareTo`의 차이는?
100+
101+
[`compareTo`와 `equals`가 일관되지 않는 `BigDecimal` 클래스]
102+
103+
```java
104+
final BigDecimal bigDecimal1 = new BigDecimal("1.0");
105+
final BigDecimal bigDecimal2 = new BigDecimal("1.00");
106+
107+
final HashSet<BigDecimal> hashSet = new HashSet<>();
108+
hashSet.add(bigDecimal1);
109+
hashSet.add(bigDecimal2);
110+
111+
System.out.println(hashSet.size());
112+
113+
final TreeSet<BigDecimal> treeSet = new TreeSet<>();
114+
treeSet.add(bigDecimal1);
115+
treeSet.add(bigDecimal2);
116+
117+
System.out.println(treeSet.size());
118+
119+
// 실행결과
120+
hashSet: 2
121+
treeSet: 1
122+
```
123+
124+
- `HashSet`과 `TreeSet`은 서로 다른 메서드로 객체의 동치성을 비교한다.
125+
126+
- `HashSet`은 `equals`를 기반으로 비교하기 때문에 추가된 두 `BigDeciaml`이 다른값으로 인식되어 크기가 `2`가 된다.
127+
128+
- 반면에, `TreeSet`은 `compareTo`를 기반으로 객체에 대한 동치성을 비교하기 때문에 같은값으로 인식되어 
129+
130+
`compareTo`가 `0`을 반환하기 때문에 크기가 `1`이 된다.
131+
132+
<br/>
133+
134+
## compareTo 메서드에서 관계연산자 (<, >)를 사용하지 않는것을 추천한다.
135+
136+
- 박싱된 기본 타입 클래스들에 새로 추가된 정적 메서드 `compare`를 대신 이용한다.
137+
138+
- 관계연산자(`<`,`>`)는 오류를 유발할 가능성이 있기때문에 추천하지 않는다.
139+
140+
141+
<br/>
142+
143+
### 클래스에 핵심 필드 여러개일때 비교
144+
145+
클래스에 핵심필드가 여러개라면 가장 핵심적인 필드부터 비교하자.
146+
147+
교 결과가 `0`이 아니라면, 즉 순서가 결정되면 바로 결과를 반환하면 된다.
148+
149+
똑같지 않은 필드를 찾을 때 까지 비교해나가도록 구현하면 된다.
150+
151+
<br/>
152+
153+
## Comparator 인터페이스
154+
155+
자바 8에서 Comparator 인터페이스가 일련의 비교자 생성 메서드와 메서드 연쇄방식으로 비교자를 생성할 수 있게 되었다.
156+
157+
- 비교자들은 `compareTo` 메서드를 구현하는데 활용될 수 있다.
158+
159+
이 방식은 간결하지만 약간의 성능 저하가 뒤따른다.
160+
161+
자바의 정적 임포트 기능을 활용하면 정적 비교자 생성 메서드들을 그 이름만으로
162+
163+
사용할 수 있어 코드가 훨씬 깔끔해진다.
164+
165+
- `Comparator`는 `comparingInt`와 `thenComparingInt`등의 숫자용 기본 타입을 커버하는 보조 생성 메서드들을 가지고 있다.
166+
- `comparing`와 `thenComparing`이란 객체 참조용 비교자 생성 메서드 또한 가지고 있다.
167+
168+
<br/>
169+
170+
## 정리
171+
172+
순서를 고려해야하는 값 클래스를 작성한다면 꼭 `Comparable` 인터페이스를 구현하여
173+
174+
그 인스턴스들을 쉽게 정렬하고, 검색하고, 비교 기능을 제공하는 컬렉션과 어우러지도록
175+
해야한다.
176+
177+
<br/>
178+
179+
`compareTo` 메서드에서 필드의 값을 비교할 때 `<`와`>` 연산자는 지양해야 한다.
180+
181+
그 대신 박싱된 기본 타입 클래스가 제공하는 정적 `compare` 메서드나 `Comparator`가 제공하는 비교자 생성 메서드를 이용하자.

0 commit comments

Comments
 (0)