이 포스트 에서는 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 를 이용하여 역순으로 정렬해 보겠습니다.
RevereSort 라는 이름의 Comparator interface를 implements 한 클래스 생성 및 compare method override.
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) { 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 }; 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); Collections.reverse(numbers); Collections.sort(numbers, Collections.reverseOrder()); assertEquals(numbers, expected); }
지금까지는 Comparable과 Comparator의 기본적인 사용법을 알아 봤습니다. 실무에서는 위와 같이 사용하는 경우는 List 를 사용하는 경우를 제외하고는 거의 없을것 같습니다. 보통의 경우 내가 만든 클래스에 compare를 하는 경우에 많이 쓰이게 될 텐데 아래 예제 코드를 작성 했습니다.