Java

[Java] Comparator와 Comparable

씬프 2021. 5. 25. 13:45
반응형

Comparator와 Comparable은 모두 인터페이스로 컬렉션을 정렬하는데 필요한 메서드를 정의하고 있다.

Comparable을 구현하고 있는 클래스들은 같은 타입의 인스턴스끼리 서로 비교할 수 있는 클래스들이다.

기본적으로 오름차순으로 정렬되도록 구현되어 있다.

 

인터페이스 소스 코드

public interface Comparator {
  int compare(Object o1, Object o2);
  boolean equals(Object obj);
}

public interface Comparable {
  public int compareTo(Object o);
}

Comparator는 compare 메서드와 equals 메서드를 정의하고 있지만, equals 메서드는 모든 클래스가 가지고 있는 공통 메서드이기 때문에 compare 메서드만 구현하면 된다.

 

Comparable

기본 정렬기준을 정의하는데 사용된다.

Integer와 같은 wrapper 클래스와 String, Date와 같은 클래스에 정의되어 있다.

public final class Integer extends Number implements Comparable {
  ...
  public int compareTo(Object o) {
    return compareTo((Integer) o);
  }
  
  public int compareTo(Integer anotherInteger) {
    int thisVal = this.value; // 객체에 저장된 값
    int anotherVal = anotherInteger.value; // 비교대상, 다른 객체에 저장된 값
    return (thisVal < anotherVal ? -1 : (thisVal == anotherVal ? 0 : 1));
    // 비교 대상이 크면 -1, 같으면 0, 비교대상이 작으면 1
  }
  ...
}

클래스를 새로 정의해 Comparable을 구현하도록 하고 compareTo 메서드를 구현하면 정의한 기준에 따라 객체들을 정의할 수 있다. (음수면 비교대상이 크다, 같으면 0, 비교대상이 작으면 양수)

 

Comparator

기본 정렬 기준 외에 다른 기준으로 정렬하고자 할 때 사용한다.

Comparator에 정의된 static 메서드를 통해 자주 사용하는 정렬 기준을 사용할 수 있다.

reverseOrder() : 내림차순으로 정렬한다. (오름차순은 기본이지만, naturalOrder()로 정의되어 있다.)

import java.util.*;

class Main {

  public static void main(String[] args) {
    
    Integer[] arr = {1,2,4,1,6,2,73,57,2};

    Arrays.sort(arr);
    System.out.println(Arrays.toString(arr));
	//[1, 1, 2, 2, 2, 4, 6, 57, 73]

    Arrays.sort(arr, Comparator.reverseOrder());
    System.out.println(Arrays.toString(arr));
    //[73, 57, 6, 4, 2, 2, 2, 1, 1]
  } // end main
}

reverseOrder()의 경우 Comparable을 구현한 클래스 객체에 사용할 수 있다.

reverseOrder()는 Collections 클래스에도 정의되어 있다.

 

만약 클래스 객체가 아닌 기본 정수형 int 배열을 정렬할 경우는 Integer 클래스로 감싸주고 적용해야 한다.

 

언제 Comparable을 사용하고, 언제 Comparator를 사용할 것인가?

sort() 메서드를 사용할 때, 해당 클래스에 Comparable을 구현하고 있어야 한다. (기본정렬 기준)

기본 정렬 기준이 없을 때, Comparator을 통해 정렬 기준을 정의해 사용할 수 있다.

public class Student {
  private int score;
  private String name;
  
  public Student(String name, int score) {
    this.name = name;
    this.score = score;
  }

  public int getScore() {
    return this.score;
  }

  public String getName() {
    return this.name;
  }
}

위와 같은 학생의 점수와 이름에 대한 정보를 담은 클래스가 있다. Comparable을 구현해 compareTo() 메서드로 정렬 기준을 정의할 수 있지만, 클래스를 수정할 수 없다는 상황이라고 가정하자.

 

입력된 5명의 학생의 점수를 오름차순으로 정렬하기 원한다.

import java.util.*;

class Main {

  public static void main(String[] args) {
    
    Student[] arr = new Student[5];
    arr[0] = new Student("A", 100);
    arr[1] = new Student("B", 90);
    arr[2] = new Student("C", 40);
    arr[3] = new Student("D", 70);
    arr[4] = new Student("E", 85);

    Comparator<Student> c = new Comparator<>() {
      @Override
      public int compare(Student s1, Student s2) {
        return s1.getScore() - s2.getScore();
      }
    };

    Arrays.sort(arr, c);
    
    for (Student a : arr) {
      System.out.printf("%s %d %n", a.getName(), a.getScore());
    }

  } // end main
}

Comparator를 구현해 점수에 따라 정렬되도록 compare() 메서드를 정의한다.

그리고 sort() 메서드에 구현된 Comparator 객체를 전달한다.

 

이 때, 새로 객체를 선언하고 정의해야 하는데, Comparator 인터페이스는 compare() 메서드만 정의해도 된다.

람다식으로 간단하게 식을 정의할 수 있다.

import java.util.*;

class Main {

  public static void main(String[] args) {
    Student[] arr = new Student[5];
    arr[0] = new Student("A", 100);
    arr[1] = new Student("B", 90);
    arr[2] = new Student("C", 40);
    arr[3] = new Student("D", 70);
    arr[4] = new Student("E", 85);

    Arrays.sort(arr, (s1, s2) -> s1.getScore() - s2.getScore());
    
    for (Student a : arr) {
      System.out.printf("%s %d %n", a.getName(), a.getScore());
    }

  } // end main
}

Comparator를 선언하고 compare를 정의하는 단계 없이 람다식으로 한번에 정의할 수 있다.

 

Comparable클래스를 직접 정의하고, 기본적인 정렬 기준을 정의하고 싶을 때 사용하고,

Comparator클래스를 직접 정의할 수 없거나, 기본적인 정렬 기준 외에 다른 기준을 정의하고 싶을 때 사용한다.

 

주의할 점

Colections.sort()

static <T> void  sort(List<T> list, Comparator<? super T> c)

Collections의 sort() 메서드는 매개변수로 list와 Comparator 객체를 전달 받는다.

 

Arrays.sort()

static void sort(type[] arr) : type은 기본 자료형 (int, long, double, 등등)

static void sort(Object[] arr)

static<T> void sort(T[] arr, Comparator c)

Arrays의 sort() 메서드는 배열을 정렬한다. 객체 배열도 정렬할 수 있다.

다른 정렬 기준을 적용하기 위해 Comparator 객체를 전달할 때는 객체 배열에 적용된다.

 

 

'Java' 카테고리의 다른 글

[Java] HashMap 클래스  (0) 2021.05.27
[Java] TreeSet 클래스  (0) 2021.05.26
[Java] Arrays 클래스  (0) 2021.05.24
[Java] LinkedList  (0) 2021.05.22
[Java] ArrayList  (0) 2021.05.21