java sort 관련 회고

알고리즘 문제를 풀거나 자바 공부를 하면서 배열, 컬렉션을 배우다보면 꼭 등장하는 녀석이 바로 정렬이다.  이는 곧 다수의 데이터를 다루기에 정렬을 할 수 있는 1차 조건이 만족되는 것이다. 이때 기본적으로 오름차순 정렬을 따른다. 그러나 상황에 따라서는 내림차순으로 정렬을 해야할 수도 있고, 문득 Comparator, Comparable을 공부하면서 내림차순으로 정렬되도록 시도해보고 싶었다.  우선은 간단하게 int[] 배열을 통해서 Arrays class에 있는 sort메서드를 활용해서 오름차순을 Test해봤다. 기본 정렬이기에 아주 Easy하게 정렬이 되었다. 그러나 sort 메서드를 보면 정렬할 기준을 매개변수로 전달해줄 수 있는 오버로딩 된 메서드도 존재한다.  바로 아래와 같은 이러한 메서드들이다.

 

 

다음과 같이 내림차순 정렬을 해보기 위해서 실제 Cpmparator 인터페이스 추상 메서드를 확인해보고 JDK 11 문서에서 오버로딩 된 메서드를 확인해봤다. 그래고 함수형 인터페이스이기에 람다식을 활용해볼 수 있었지만, 람다식보다 정렬을 위한 클래스를 하나 만들고 이를 활용하여 진행해보았다.

 

우선 첫번째 시도는 이렇다.

// 접근 -> 우선 지네릭스를 비워두고 매개변수 타입을 int로하여 차이를 비교했다.
class Reverse implements Comparator{
    @Override
    public int compare(int o1, int o2) { 
        return o2 - o1;
    }
}

첫번째 접근에 있어서 다음과 같이 빨간줄이 생기는 것을 볼 수 있었다. 

 

다음으로 두번째 시도이다.

// 접근 -> 지네릭스 타입을 지정해주고 매개변수 타입도 Wrapper 클래스로 변경
class Reverse implements Comparator<Integer>{

    @Override
    public int compare(Integer o1, Integer o2) {
        return o2-o1;
    }
}

class Test{
    public static void main(String[] args) {
        int[] arr = {1,50,3,4,21,80,100,20};
        Arrays.sort(arr,new Reverse());
        System.out.println(Arrays.toString(arr));
    }
}

클래스 생성까지는 문제 없지만, 실제로 정렬 방식으로 지정하려고 하니 다음과 같이 빨간불이 생성되었다. 사실 첫 번째 시도는 매개변수 타입이 T였던 것을 감안해서 당연히 기본형 변수 타입으로는 안되겠구나 생각이 들어서 두번째 적용을 도출하기까지는 이해할 수 있었다. 그러나 두 번째 시도를 한 후 한참동안 왜 이게 안되지하며 계속 고민을 했다. 한참을 고민하면서 마우스를 올려놓고 바라보는데 다음과 같은 부분을 확인하게 되었다.

 

매개변수로 요구되는 타입과 제공하려는 타입간에 불일치가 있는 것이다.

 

세번째 시도

// 접근 -> Integer[] 타입으로 참조변수 타입지정
class Test{
    public static void main(String[] args) {
        Integer[] arr = {1,50,3,4,21,80,100,20};
        Arrays.sort(arr,new Reverse());
        System.out.println(Arrays.toString(arr));
    }
}

잘 되는 것을 확인했다. 우선은 접근은 맞았기에 한 가지 더 생각해 본 것은 int[] 형으로 되어 있는데 현재는 직접 Integer[]로 타입을 지정해 주었다. 우선은 선언과 동시에 값을 초기화 할 때는 무리가 없었다. 그러나 알고 싶은 것은 int[] 형 배열을 사용하다가 정렬을 하고자 하는 경우가 발생할 경우 어떻게 변경할 수 있을까였다. 먼저는 Integer 클래스에 마치 컬렉션처럼 기본형 배열을 받아서 변환하는 무엇인가 없나하고 찾았는데, 결과적으로 찾지는 못했다. 이에대해서 생각해보면 Integer 클래스 자체가 하나의 기본형 값을 클래스로 덮은 Wrapper 클래스이며 Integer[] 같은 경우는 이러한 클래스로부터 만들어지는 객체들을 다루는 객체배열이다. 컬렉션과는 다르게 접근했어야 했다.

 

다음으로는 배열의 타입을 변환하기 위하여 stream()을 찾아봤다. 접근은 IntStream -> Stream<Interger>로 변환하기 위해 boxed()를 활용하고 toArray(Interger[] :: new)를 활용하여  Integer[] 배열을 만들어서 반환하는 것이었다.

 

다음과 같이 깔끔하게 성공했다.

 

오늘 다음과 같이 TIL을 정리한 것은 기존에도 알고리즘을 풀면서 이와같이 역순으로 정렬하고 싶었던 적이 있었고, 당시에는 구글링을 통해서 찾아서 적용해본 기억이 있다. 그러나 이번에 다시 진행하면서 내림차순 정렬을 하는 방법에 있어서 감이 안생겨서 한번쯤 정리하고 가야겠다 싶어서 하게되었다. 단순 내림차순 정렬이지만, 넓게는 정렬 기준을 지정하고 정렬하는 방법에 대해서 터득하고 싶었고, Comparator 인터페이스도 실제로 열어보면서 지네릭스 타입과 compare() 호출 시 T[] 타입이기에 기본형으로 넣어 줄 수 없다는 것도 알게 되었다. 처음 접근으로는 오토박싱, 언박싱에 대한 개념으로 접근했는데, 접근에 있어서 지네릭스 부분을 간과한 것 같다.