[사이드 프로젝트] 함수형 프로그래밍 익히기 With Java - Comparator

gimseonjin616·2022년 5월 12일
0

Comparator

Comparator는 두 개의 파라미터를 받는 함수다.

내부에는 compare라는 추상 함수를 가지고 있으며 이 추상 함수는 건네받은 값들을 비교해서 더 작으면 음수, 같으면 0, 크면 양수를 출력하도록 구현해야한다.

Comparator 함수는 단독으로 잘 쓰이지 않으며 Collection 내부의 sort와 함께 쓰인다.

Collection 내부 sort 형태는 아래와 같다.

    public static <T> void sort(List<T> list, Comparator<? super T> c) {
        list.sort(c);
    }

List 내부의 Sort와 매핑해주는 것이 전부지만 결국 Java 내부에서 정렬할 때, Comparator를 쓰는 것을 알 수 있다.

Java 얕은 복사 vs 깊은 복사

자바에서 메모리는 스택 메모리와 힙 메모리로 구분된다.

스택 메모리에서는 원시값, 또는 식별자(변수명) 등을 저장하며 구현된 객체(클래스 등)는 힙 메모리에 저장된다.

이때 메모리 낭비를 막기 위해서 객체를 복사할 때, "두 개의 식별자가 하나의 객체를 가르키도록" 하는 얕은 복사를 쓴다.

그러나 얕은 복사를 사용할 시, 메모리가 낭비되진 않지만 예상치 못한 사이드 이펙트가 발생할 수 있다.

특히 이 사이드 이펙트를 방지하기 위해 사용한다고 볼 수 있는 함수형 프로그래밍에서 얕은 복사를 사용하기엔 조심스럽다.

따라서 기존 객체의 변경을 주지 않는 깊은 복사를 활용한 별도의 sort 함수를 구현해서 사용해볼 것이다.

Array.sort()

Collection Sort 내부의 list.sort()를 타고 들어가면 다음과 같이 구현되어 있다.

    default void sort(Comparator<? super E> c) {
        Object[] a = this.toArray();
        Arrays.sort(a, (Comparator) c);
        ListIterator<E> i = this.listIterator();
        for (Object e : a) {
            i.next();
            i.set((E) e);
        }
    }

Sorting 순서를 보면 다음과 같다.

1) list -> array로 변환
2) array 단위로 정렬
3) list 내부 iterator 초기화
4) 정렬된 array -> list로 깊은 복사

즉 List Sort 내부에서도 깊은 복사를 사용하기 때문에 이 코드를 가져와서 다음과 같이 깊은 복사를 활용한 Sort 함수를 만들었다.

public class main {
    public static void main(String[] args){
        List<User> userList = new ArrayList<>();
        userList.add(new User(1, "kim"));
        userList.add(new User(3, "Pack"));
        userList.add(new User(2, "Lee"));
        userList.add(new User(4, "Jeon"));

        Comparator<User> idComparator = (user1, user2) -> user1.getId() - user2.getId();

        System.out.println(userList);
        System.out.println(sort(userList, idComparator));
    }

    public static <T> List<T> sort(List<T> list, Comparator<T> processor){
        List<T> newList = new ArrayList<T>();

        Object[] tmp_list = list.toArray();
        Arrays.sort(tmp_list, (Comparator) processor);

        for (Object l : tmp_list) {
            newList.add((T) l);
        }

        return newList;
    }
}

업로드중..

기존 userList를 출력해보면 정렬된 객체와 다르게 값이 바뀌지 않은 것을 볼 수 있다.

profile
to be data engineer

0개의 댓글