자바에서 primitive type(기본형) 중 OO.Compare이 있는 경우를 제외하고 객체 비교를 할 때 compareTo 또는 Comparator를 이용한다.
그중 Comparator의 경우 (특정 객체).sort(), Collections.sort함수 또는 Arrays.sort함수를 쓸 때 파라미터로 정렬기준(내림차순, 오름차순)으로 많이 활용하므로 "무조건" 익숙해지면 좋은 인터페이스이다.
1. Comparator에 관하여
Comparator 인터페이스의 경우 f3을 누르거나 ctrl + 마우스 좌클릭을 할 경우 아래와 같은 내용을 확인할 수 있다.
인터페이스이므로 결국 해당 compare함수를 재정의해서 쓰라는 뜻이다.
반드시 아래와 같이 Override 하여 사용하여야 한다. 안하면 컴파일러가 화가 나있을 것이다.
public class ISBNDECS implements Comparator<Book>{
// compare 함수 overriding으로 재정의
@Override
public int compare(Book o1, Book o2) {
int reisbn = o1.getIsbn().compareTo(o2.getIsbn());
if(reisbn != 0 ) {
return -reisbn;
} else {
int req = Integer.compare(o1.getQuantity(), o1.getQuantity());
return -req;
}
}
// comparator를 통해 객체 정렬
@Override
public Book[] getISBNDESCList() {
books.sort(new ISBNDECS());
return books.toArray(new Book[books.size()]);
}
}
compare 함수의 선언부를 보면 두 개의 파라미터를 받아야 하며 int형으로 return을 하는 것으로 보인다.
여기서 두 개의 파라미터는 비교할 두 객체를 의미하며 int는 1, 0, -1 값중 하나에 해당한다.
(반환형 분류)
1 : o1 > o2
0 : o1 == o2
-1 : o1 < o2
여기서 크다 작다는 단순히 특정 값이 크다, 작다 일수도 있지만 String형의 경우 사전적 순서를 의미하므로 (lexicographical하다라고 한다.) 사전상의 오름차순, 내림차순 정렬을 할 때 참고해야 한다.
(항상 String형은 예외가 있는 것 같다.)
더 깊숙하게 알면 좋겠지만 본인 경험상 실제로 사용할 때는 그냥 오름차순을 원할 때는 o1 < o2 인 경우로 return값이 -1이 되게 만들고, 내림차순일 때는 o1 > o2 인경우로 return 값을 1로 만들어서 쓴다.
그리고 0(두 객체가 같을 값일 경우) 다른 변수들을 비교하여 (파이썬의 lambda처럼) 그걸 기준으로 정렬을 해서 쓰면 된다.(모든 게 같은 값이면 애초에 정렬할 필요도 없으니 신경 안 써도 될 것 같다.)
심화버전으로 익명클래스 또는 lambda식으로 정렬을 할 수도 있으니 참고하시라.(아 파이썬 그립다...)
// 익명 클래스 활용 (Collections 라이브러리 import해서 써야함)
Collections.sort(books, new Comparator<Book>() {
@Override
public int compare(Book a, Book b){
// a, b가 서로 뺄 수 있는 값이 있을 경우
return a - b;
// a, b 자체로는 연산 불가능하고 멤버변수 연산이 가능할 때
return a.getPrice - b.getPrice;
}
});
// lambda 활용
// a, b가 서로 뺄 수 있는 값이 있을 경우
books.sort((a, b)-> a - b);
// a, b 자체로는 연산 불가능하고 멤버변수 연산이 가능할 때
books.sort((a, b)->{return a.getPrice() - b.getPrice();});
2. compareTo함수(Comparable 인터페이스)에 관하여
Comparable 인터페이스의 경우 f3을 누르거나 ctrl + 마우스 좌클릭을 할 경우 아래와 같은 내용을 확인할 수 있다.
Comparator의 compare 함수와 같이 이 친구도 compareTo를 재정의 해서 "써달라"고 애원하고 있다.
public class Book implements Comparable<Book>{
public int compareTo(Book b2) {
int reisbn = this.getIsbn().compareTo(b2.getIsbn());
if(reisbn !=0) {
return reisbn;
}else {
return Integer.compare(this.getQuantity(), b2.getQuantity());
}
}
}
comparator 람다나 익명클래스에서 비교할 수 없는 객체일 경우 비교할 수 있는 멤버변수 끼리 연산해서 return값 받으라고 표기해 뒀으나 해결책이 드디어 나왔다.
comparable 인터페이스를 구현하고, compareTo 함수를 클래스에 정의 하는 순간 그 객체는 비교가 가능한 객체로 돌변한다.
compareTo 함수의 선언부를 보면 Comparator의 compare 함수의 선언부와 같이 int 리턴타입으로 지정되어 있다.
맞다. 똑같은 분류의 값(1,0,-1)을 반환한다. 다른 점은 파라미터 갯수 일 뿐이다. 아무래도 프로그래밍 언어는 영어 위주다보니 영어 자체로 보는게 직관적이다.
compare A to B = A와 B를 비교하다에서 A compareTo B => A는 주어 B는 비교할 대상(객체)로 A.compareTo(B)로 쓰면 된다.
위쪽의 소스코드와 같이 Book 클래스에는 Comparable 인터페이스 구현 및 compareTo 함수가 재정의 되어 있으므로 아래 소스코드처럼 정렬할 때 쓰면 된다.
또한 그냥 특정 객체와 comprareTo 내부 로직대로 비교하고 싶을 때는 그냥 a.compareTo(b)와 같이 쓰면 된다.
public Book[] getISBNSortList() {
books.sort(new ISBNACS());
return books.toArray(new Book[books.size()]);
}
// 그냥 특정 객체끼리 비교하고 싶을 때
a.compareTo(b); // 1, 0, -1이 반환됨
이제 다 끝났다.
아래의 소스코드를 보면 아름답지 아니한가?
// 익명 클래스 활용 (Collections 라이브러리 import해서 써야함)
Collections.sort(books, (a, b) -> a - b);
// lambda 활용
// a, b가 자체적으로 비교 가능하도록 compareTo가 구현되어 있는 상태
books.sort((a, b)-> a - b);
'프로그래밍공부(Programming Study) > 자바(JAVA)' 카테고리의 다른 글
자바 버전별 특징 (0) | 2022.12.03 |
---|---|
자바답게 프로그래밍하기 (0) | 2022.10.31 |
[JAVA] W3C school java tutorial 정리 (0) | 2022.10.20 |
(JAVA/자바) 생성자와 초기화 (0) | 2022.02.20 |
댓글