Comparator Interface 공부

구창회·2023년 6월 17일
0

자바 공부 중

목록 보기
10/10

순서를 비교하고 싶을 때가 있다. 대상이 숫자라면 단순하게 크기를 비교하면 되겠지만, 객체라면 어떻게 비교를 해야 하지? 라는 질문이 우선한다.

우리는 우선 객체의 어떤 것 을 기준으로 하여 비교를 할 지 정해야 한다.

그리고 그것을 가능하게 하는 자바 구현체가 바로 Comparator Interface 이다.


@FunctionalInterface
public interface Comparator<T> {
 	int compare(T o1, T o2);
}

FuntionalInterface Annotation 이 붙어 있는 것을 확인 할 수 있다.
Interface 가 하나의 abstract method 만을 가질 때 FuntionalInterface 가 붙는다.

abstract 함수를 보면 제네릭한 T 타입의 인자 o1 과 o2 를 넘겨받아 int 를 리턴하는 형태를 볼 수 있다.

그리고 리턴된 int 로 우리는 비교 결과를 알 수 있다.

compare 함수의 리턴값 int 로 우리는 비교 결과를 알 수 있다

  • 음수면 o1 < o2
  • 0 일 경우 o1 = o2
  • 양수면 o1 > o2

Comparator 를 사용할 때를 가정해서 풀어서 쓰자면,

오름차순으로 sort 하는 상황에서 o1 이 o2 보다 앞에 배치되야 할 때는

compare 함수가 o1, o2 를 인자로 받고 음수를 리턴해주어야 된다 고 파악할 수 있다


Compartor 사용해보기


우선 아래와 같은 Human 클래스를 만들어 준다. 내부에 이름, 키, 나이 필드를 가지고 있다.
또한 getter 만 사용할 것이고, println 찍기 편하라고 toString 함수도 재정의 하였다.

public class Human {
    String name;
    int height;
    int age;

    public Human(String name, int height, int age) {
        this.name = name;
        this.height = height;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public int getHeight() {
        return height;
    }

    public int getAge() {
        return age;
    }
    
    @Override
    public String toString() {
        return "Human{" +
                "name='" + name + '\'' +
                ", height=" + height +
                ", age=" + age +
                '}';
    }
}

메인함수에서 Humans 객체들만을 담는 Humans 라는 리스트를 만들어서 값을 일부 담아보았다.

public class Main {
    public static void main(String[] args) {
        List<Human> humans = new ArrayList<>();
        humans.add(new Human("Alice", 165, 18));
        humans.add(new Human("Chalie", 180, 25));
        humans.add(new Human("Jackson", 170, 15));
        humans.add(new Human("Joy", 177, 19));
    }
}

이제 humans 리스트에 있는 Human 객체들을 이름 순으로, 나이 순으로, 키 순으로 정렬해볼 것이다.

정렬할 때 사용할 함수는 Collections 가 제공하는 sort 함수이다.

함수를 찾아 들어가보면 요렇게 되어있다.

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

제네릭한 T 타입의 리스트와,
제네릭한 T 타입 또는 그 super 클래스 타입들을 인자로 받는 Comparator c 를
파라미터로 받는다.

Params c – the Comparator used to compare list elements. A null value indicates that the elements' natural ordering should be used.

쉽게말해, Comparator 가 알려준 방식으로 순서 비교를 하여 정렬하겠다 라는 뜻이다

위에 서두에서 말했듯이, 단순한 int 라면 숫자의 크기 비교를 통해서 순서비교가 가능하겠지만, 객체라면, 객체의 어떤 속성으로 어떻게 비교를 할지 우리가 따로 정해야 한다. Comparator 는 이런 상황에서 사용하는 것이다.

그럼 사용해보자

System.out.println("Before sort");
System.out.println(humans);

Comparator<Human> comparateAge = (Human h1, Human h2) -> {
      return h1.getAge() - h2.getAge();
}; 

Collections.sort(humans, comparateAge);
System.out.println("After sort");
System.out.println(humans);

위에서는 람다식으로 Comparator 를 구현한 익명함수를 만들어서 사용하였다. 하지만 따로 클래스를 구현하여 사용하여도 무방.

Compare 함수의 리턴값을 Human 객체들의 나이의 차이로 리턴한 것을 볼 수 있다.

만약 h1 이 나이가 더 작다면, 음수가 리턴되고, h1 은 h2 보다 앞에 위치하게 되는 방식이다.(h1 이 더 작다고 판단)

실행 결과는 아래처럼, 나이로 잘 정렬되어 나오는 것을 볼 수 있다.

이름 으로 정렬하는 경우는 조금 다르다.

String 에서 제공하는 compareTo 메소드를 사용해야 한다.

public class Main {
    public static void main(String[] args) {
        List<Human> humans = new ArrayList<>();

        humans.add(new Human("Joy", 177, 19));
        humans.add(new Human("Chalie", 180, 25));
        humans.add(new Human("Jackson", 170, 15));
        humans.add(new Human("Alice", 165, 18));

        System.out.println("Before sort");
        System.out.println(humans);

        Comparator<Human> comparateAge = (Human h1, Human h2) -> h1.getName().compareTo(h2.getName());


        Collections.sort(humans, comparateAge);
        System.out.println("After sort");
        System.out.println(humans);


    }
}

String 의 compareTo 메소드는 알파벳 어순을 비교해, 어순이 더 빠를 때에는 음수를 리턴해 준다.

결과는 역시 잘 알파벳 이름 순으로 정렬되어 나오는 것을 확인 할 수 있다.

profile
백엔드 엔지니어 프로 지망생

0개의 댓글