Comparable과 Comparator

이 포스트 에서는 Comparable 과 Comparator 두 Interface의 차이점에 대해서 알아 보겠습니다.

두 Interface의 가장 큰 차이점은 Comparable 은 자연스러운 순서로 정렬할 때 사용하고, Comparator는 원하는 대로 정렬 순서를 정하고 싶을 때 사용한다는 점 입니다.

가장 정확한 정의를 찾기 위해서는 자바 공식 문서를 찾아보는 습관을 들이는게 좋습니다.

Comparable (Java Platform SE 8 )

Comparator (Java Platform SE 8 )

int type의 배열을 순서대로 정렬해 보겠습니다.
아래 테스트 코드를 돌려보면 자연스러운 순서 (natural ordering) 이라는 말이 무슨 말인지 이해 됩니다.

1
2
3
4
5
6
7
8
@Test
public void sortInteger() {
int[] numbers = { -8, -10, 11, 0, 1, 5, -5, 7};
int[] expected = { -10, -8, -5, 0, 1, 5, 7, 11};

Arrays.sort(numbers);
assertArrayEquals(expected, numbers);
}

여기 에 나와 있듯이

Lists (and arrays) of objects that implement this interface can be sorted automatically by Collections.sort (and Arrays.sort).

Lists나 Arrays의 .sort 함수를 사용할 경우 Comparable을 implement한 정렬이 이뤄 집니다.
int형 배열을 선언하고
Arrays.sort로 정렬 해 보았습니다.
작은수 -> 큰수로 정렬이 될것이라 예상하고 expected 배열에 미리 순서대로 적어보고 assertArrayEquals로 검증해 보니
Junit test case가 pass 되었습니다.

※이 블로그에 쓰여질 대부분의 소스코드는 Junit을 이용한 테스트 케이스로 진행 할 예정 입니다.

이번에는 Comparator 를 이용하여 역순으로 정렬해 보겠습니다.

  1. RevereSort 라는 이름의 Comparator interface를 implements 한 클래스 생성 및 compare method override.
  2. testcase를 pass 하는지 확인
1
2
3
4
5
6
7
8
9
10
11
12
13
import java.util.Comparator;

public class ReverseSort implements Comparator<Integer>{

@Override
public int compare(Integer o1, Integer o2) {
//기본적으로 첫번째 인자인 o1이 두번째 인자인 o2보다 크면 음수,
//같으면 0, o2가 더 크면 양수를 리턴하는게 규칙 입니다.
//저는 역순으로 정렬하고 싶기 때문에 o2 - o1을 리턴 하도록 하겠습니다.
return o2 - o1;
}

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Test
public void reverseSortInteger() {

int[] numbers = { -8, -10, 11, 0, 1, 5, -5, 7};
int[] expected = { 11, 7, 5, 1, 0, -5, -8, -10};
//1.7 이하에서 테스트를 한다면 다음과 같이 numbers와 expected를 List로 만드는게 정신건강에 좋겠습니다.
//List<Integer> numbers = Arrays.asList(-8, -10, 11, 0, 1, 5, -5, 7);
//List<Integer> expected = Arrays.asList(11, 7, 5, 1, 0, -5, -8, -10);
List<Integer> numberlist = Arrays.stream(numbers).boxed().collect(Collectors.toList());
List<Integer> expectedlist = Arrays.stream(expected).boxed().collect(Collectors.toList());
Collections.sort(numberlist, new ReverseSort());

assertEquals(numberlist, expectedlist);

}

저는 지금 Java8 환경에서 코딩을 하고 있기 때문에 ReversSort 클래스를 만들지 않고도
사실 아래와 같이 간단하게 lamda를 이용할 수도 있습니다.

lamda를 이용해 보기 전에 먼저 Java7에서도 위와같이 클래스를 따로 만들지 않고 inline으로 코드를 짜 보면 아래와 같습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Test
public void reverseSortInteger() {
List<Integer> numbers = Arrays.asList(-8, -10, 11, 0, 1, 5, -5, 7);
List<Integer> expected = Arrays.asList(11, 7, 5, 1, 0, -5, -8, -10);

Collections.sort(numberlist, new Comparator<Integer>() {
@Override
public int compare(Integer arg0, Integer arg1) {
return arg1-arg0;
}
});
assertEquals(numberlist, expectedlist);

}

위코드를 lamda를 이용하면 아래와같이 간단하게 표현할 수 있습니다.

1
2
3
4
5
6
7
8
9
10
11
@Test
public void reverseSortIntegerWithLamda() {

List<Integer> numbers = Arrays.asList(-8, -10, 11, 0, 1, 5, -5, 7);
List<Integer> expected = Arrays.asList(11, 7, 5, 1, 0, -5, -8, -10);

numbers.sort((o1, o2)->o2-o1);

assertEquals(numbers, expected);

}

너무 어렵고 다 귀찮다!!! 고 하면 다음과 같이 reverse 함수를 사용하거나 미리 정의된 Comparator를 사용하는 방법도 있습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Test
public void reverseSortIntegerWithCollections() {

List<Integer> numbers = Arrays.asList(-8, -10, 11, 0, 1, 5, -5, 7);
List<Integer> expected = Arrays.asList(11, 7, 5, 1, 0, -5, -8, -10);

Collections.sort(numbers);
/*reverse 함수 사용*/
Collections.reverse(numbers);
/*미리 정의된 comparator 사용*/
Collections.sort(numbers, Collections.reverseOrder());

assertEquals(numbers, expected);

}

지금까지는 Comparable과 Comparator의 기본적인 사용법을 알아 봤습니다. 실무에서는 위와 같이 사용하는 경우는 List 를 사용하는 경우를 제외하고는 거의 없을것 같습니다.

보통의 경우 내가 만든 클래스에 compare를 하는 경우에 많이 쓰이게 될 텐데 아래 예제 코드를 작성 했습니다.

Share