본문 바로가기

java

[210116] java comparable & comparator

.

 

Comparable과 Comparator 모두 interface로 array나 collection 요소를 정렬하는 데 사용한다. 하지만 사용하는 상황 등에서 약간의 차이점이 있다. 

 

Comparable - Comparator 간의 차이점 


java.lang.Comparable

1) 사용 시 인스턴스에 해당되는 클래스에 영향을 미치며, 실제로 클래스를 변경시킨다. 

2) compareTo 메소드를 제공한다. 

3) Collections.sort(list) 메소드를 사용해서 정렬을 수행한다. 사용 시 인스턴스 클래스에 override한 compareTo 메소드를 기반으로 요소를 비교한다. 

 => 클래스에 대한 기본적인 정렬 기준을 생성할 때 사용한다. 

 

java.util.Comparator

1) 함수적 인터페이스로 람다 식이나 메소드 참조에 대한 매개변수로 사용할 수 있다.

2) 하나의 추상 메소드로 compare과, java.lang.object에서 상속받은 equals 메소드와 다른 다양한 디폴트 메소드를 포함하고 있다. 

3) Collections.sort(list, Comparator) 메소드를 사용해서 정렬을 수행한다. 

=> 기본적인 정렬 기준에 예외되는 정렬 기준을 새로 생성할 때 사용한다. 주로 익명 클래스로 만들어진다. 

 

 

 

Comparable 사용 예제


실습을 위해 작성한 전체 코드는 아래와 같다. 

public class SortExample {

    public static class Person implements Comparable<Person>{

        String name;
        int age;
        int salary;

        public Person(String name, int age, int salary) {
            this.name = name;
            this.age = age;
            this.salary = salary;
        }

        @Override
        public int compareTo(Person person) {
            if(this.age == person.age){
                return 0;
            }else{
                return this.age > person.age ? -1 : 1;
            }
        }

        @Override
        public String toString() {
            return "Person{" +
                    "name='" + name + '\'' +
                    ", age=" + age +
                    ", saraly=" + salary +
                    '}';
        }
    }

    public static void main(String[] args) {

        List<Person> personList = new ArrayList<>();

        personList.add(new Person("a", 35, 2300));
        personList.add(new Person("b", 40, 3500));
        personList.add(new Person("c", 25, 4000));
        personList.add(new Person("d", 50, 4500));
        personList.add(new Person("e", 45, 3700));

        Collections.sort(personList);

        Iterator<Person> iterator = personList.listIterator();

        while(iterator.hasNext()){
            System.out.println(iterator.next().toString());
        }

    }

}

Person 객체는 사람의 정보를 저장한다. name, age, saraly 변수를 가진다. Comparable interface를 implement하고 compareTo 메소드를 override해서 내부를 구현해주었다. 

 

Collections.sort(personList)를 호출했을 때, 비교대상인 Person 객체에 구현된 compareTo 메소드를 기반으로 정렬을 수행한다. compareTo 메소드가 없으면 Collections.sort(personList)를 수행할 수 없다. 

 

* int CompareTo(T o)

매개변수로 들어온 Object를 자신의 Object와 비교한다. 

- return 

  • 음수 : 매개변수 값이 자신의 값보다 크다. 
  • 0 : 매개변수 값과 자신의 값이 같다. 
  • 양수 : 매개변수 값이 자신의 값보다 작다. 

위 예제에서는 다음과 같이 구현했다. 

@Override
        public int compareTo(Person person) {
            if(this.age == person.age){
                return 0;
            }else{
                return this.age > person.age ? -1 : 1;
            }
        }

나이를 비교해서, 나이가 같다면 0, 매개변수로 들어온 값이 더 크다면 -1, 작다면 1을 반환한다. 

 

- 실행 결과

나이 순으로 오름차순 정렬된 것을 확인할 수 있다. 

compareTo에서 나이 비교 시의 부등호 방향을 바꾸면 내림차순 정렬도 가능하다. 

 

 

Comparator 사용 예제


이번에는, 기존의 방식과 다르게 salary를 기준으로 정렬을 수행하려고 한다. 이때 이미 구현한 compareTo의 내용을 바꿀 필요 없이, Collections.sort()에 매개변수로 Comparator<Person> 형의 익명 클래스에 compare 메소드를 구현해서 정렬에 사용할 수 있다. 

public class SortExample {

    public static class Person implements Comparable<Person>{

        String name;
        int age;
        int salary;

        public Person(String name, int age, int salary) {
            this.name = name;
            this.age = age;
            this.salary = salary;
        }

        @Override
        public int compareTo(Person person) {
            if(this.age == person.age){
                return 0;
            }else{
                return this.age < person.age ? -1 : 1;
            }
        }

        @Override
        public String toString() {
            return "Person{" +
                    "name='" + name + '\'' +
                    ", age=" + age +
                    ", salary=" + salary +
                    '}';
        }
    }

    public static void main(String[] args) {

        List<Person> personList = new ArrayList<>();

        personList.add(new Person("a", 35, 2300));
        personList.add(new Person("b", 40, 3500));
        personList.add(new Person("c", 25, 4000));
        personList.add(new Person("d", 50, 4500));
        personList.add(new Person("e", 45, 3700));

        Collections.sort(personList, new Comparator<Person>() {
            @Override
            public int compare(Person o1, Person o2) {
                if(o1.salary > o2.salary){
                    return 1;
                }else{
                    return -1;
                }
            }
        });

        Iterator<Person> iterator = personList.listIterator();

        while(iterator.hasNext()){
            System.out.println(iterator.next().toString());
        }
    }

}

Collections.sort의 인수로 personList와 Comparator 익명클래스를 함께 넘긴 것을 확인할 수 있다. 이 코드는 람다식으로도 작성할 수 있다. 

 

Collections.sort(personList, (Person o1, Person o2)-> {
            return o1.salary > o2.salary ? 1 : -1;
        });

 

* int compare(T o1, T o2)

매개변수로 받은 두 객체를 비교한다. 

o1 : 첫 번째로 비교되는 객체

o2 : 두 번째로 비교되는 객체 

- return 

음수 : 첫 번째 객체가 두 번째 객체보다 작다.

0 : 첫 번째 객체와 두 번째 객체 값이 같다. 

양수 : 첫 번째 객체가 두 번째 객체보다 크다. 

 

- 실행 결과

salary 순으로 오름차순 된 것을 확인할 수 있다. 

 

 

 

- Reference

www.javatpoint.com/difference-between-comparable-and-comparator

mkyong.com/java8/is-comparator-a-function-interface-but-it-has-two-abstract-methods/

hochulshin.com/java-comparable-comparator/

m.blog.naver.com/PostView.nhn?blogId=occidere&logNo=220918234464&proxyReferer=https%3A%2F%2Fwww.google.co.kr%2F

docs.oracle.com/javase/8/docs/api/java/lang/Comparable.html

docs.oracle.com/javase/8/docs/api/java/util/Comparator.html