It's easy, if you try

[JAVA] Comparable vs Comparator 본문

언어/자바(Java)

[JAVA] Comparable vs Comparator

s5he2 2021. 2. 21. 18:09
목차
1. Collections 의 Sort
2. Comparable
3. Comparator
4. Comparator 익명의 내부 클래스 사용하기

5. 람다식으로 표현하기

Collections.sort 사용하기

Collections.sort() 를 이용해 객체를 오름차순 또는 내림차순으로 정렬할 수 있다.

Arrays.sort()의 경우 Collection(List) 정렬은 불가능하다. 배열 객체의 경우만 가능하다.(기본은 오름차순, Arrays.sort(배열 이름, Collections.reverseOrder()); ==> 내림차순)

만약 사용자가 정렬 조건을 다시 정의하고 싶다면 1. Comparable (구현, compareTo 메소드 오버라이딩) 2. Comparator (구현, compare 메소드 오버라이딩) 두가지 방법으로 재정의할 수 있다.

Comparable

특징 : Collections.sort() 전달 인자가 1개 / 익명 클래스로 사용될 수 없음.

먼저 Comparable을 이용한 리스트 정렬을 알아보자.

class Person implements Comparable<Person>{
	private String name;
	private int age;
	private String job;
	private int score;

	public Person(String name, int age, String job, int score) {
		super();
		this.name = name;
		this.age = age;
		this.job = job;
		this.score = score;
	}

	@Override
	public int compareTo(Person o) {
		return age-o.age;
	}
}

Person 객체가 있고 이들을 나이(age) 기준으로 정렬하고 싶다면 위와 같이 코드를 작성하면 된다.

1. implements Comparable<Person>

2. 반드시 구현해야할 함수(compateTo) 오버라이딩

내림차순으로 정렬하고 싶다면 compareTo 메소드를 아래와 같이 수정한다.

@Override
public int compareTo(Person o) {
	return o.age-age;  
}

즉, 자신의 age에서 넘어온 객체의 age를 뺀 값을 반환 ==> 오름차순

    넘어온 객체의 age 에서 자신의 age를 뺀 값을 반환 ==> 내림차순 이다.

이제 main에서 이를 활용해 객체 age 기준으로 정렬해보자

1. Person[] 객체 age 기준 오름차순 정렬

public class SortTest {
	public static void main(String[] args) {
		Person []persons= {  new Person("A", 11, "학생", 100), new Person("B", 15, "학생", 90), new Person("C", 12, "학생", 76), new Person("D", 10, "학생", 80), new Person("E", 12, "학생", 85)};
		
		Arrays.sort(persons);
		System.out.println(Arrays.toString(persons));
	}
}

출력

[Person [name=D, age=10, job=학생, score=80], Person [name=A, age=11, job=학생, score=100], Person [name=C, age=12, job=학생, score=76], Person [name=E, age=12, job=학생, score=85], Person [name=B, age=15, job=학생, score=90]]

 

2. List<Person> 객체 age 기준 오름차순 정렬

public class SortTest {
	public static void main(String[] args) {
		ArrayList<Person> list = new ArrayList<>();
		list.add(new Person("A", 11, "학생", 100));
		list.add( new Person("B", 15, "학생", 90));
		list.add(new Person("C", 12, "학생", 76));
		list.add(new Person("D", 10, "학생", 80));
		list.add(new Person("E", 12, "학생", 85));
		
        Collections.sort(list);
        System.out.println(list);
		
	}
}

출력

[Person [name=D, age=10, job=학생, score=80], Person [name=A, age=11, job=학생, score=100], Person [name=C, age=12, job=학생, score=76], Person [name=E, age=12, job=학생, score=85], Person [name=B, age=15, job=학생, score=90]]

1 번과 동일하게 출력됨을 확인할 수 있다. 

여기서 만약 age가 같을 때는 score 기준으로 내림차순 정렬하고 싶다면 어떻게 하면 될까?

compareTo 함수를 아래와 같이 수정하면 된다.

@Override
public int compareTo(Person o) {
	if(age - o.age == 0) {
    	return o.score- score;
    } else {
    	return age-o.age;
    }
}

출력

[Person [name=D, age=10, job=학생, score=80], Person [name=A, age=11, job=학생, score=100], Person [name=E, age=12, job=학생, score=85], Person [name=C, age=12, job=학생, score=76], Person [name=B, age=15, job=학생, score=90]]

C 학생과 E 학생의 순서가 점수 기준으로 바뀐 것을 확인할 수 있다.

Comparator

특징 : Collections.sort() 전달 인자가 2개 / 익명 클래스로 주로 사용됨.

Comparator는 compare 메소드를 오버라이딩해 정렬 기준을 재정의한다.

class Person  implements Comparator<Person>{
	private String name;
	private int age;
	private String job;
	private int score;
	
	public Person() {
		// TODO Auto-generated constructor stub
	}

	public Person(String name, int age, String job, int score) {
		super();
		this.name = name;
		this.age = age;
		this.job = job;
		this.score = score;
	}
	
	@Override
	public int compare(Person o1, Person o2) {
		return o1.age-o2.age;
	}
}

위는 age 기준 오름차순을 재정의 한 것이다.

1. implements Comparator<Person>

2. 반드시 구현해야할 함수(compare) 오버라이딩

내림차순으로 정렬하고 싶다면 compare를 아래와 같이 재정의한다.

@Override
public int compare(Person o1, Person o2) {
	return -(o1.age-o2.age);
}

main 함수에서 age를 기준으로 오름차순 정렬하는 코드를 구현해보자.

public static void main(String[] args) {
		Person []persons= {  new Person("A", 11, "학생", 100), new Person("B", 15, "학생", 90), new Person("C", 12, "학생", 76), new Person("D", 10, "학생", 80), new Person("E", 12, "학생", 85)};

		Arrays.sort(persons, new Person());
		System.out.println(Arrays.toString(persons));

		ArrayList<Person> list = new ArrayList<>();
		list.add(new Person("A", 11, "학생", 100));
		list.add(new Person("B", 15, "학생", 90));
		list.add(new Person("C", 12, "학생", 76));
		list.add(new Person("D", 10, "학생", 80));
		list.add(new Person("E", 12, "학생", 85));
		
        Collections.sort(list,new Person());
        System.out.println(list);
}

 

여기서 발견할 수 있는 큰 차이점은 Comparable 의 경우 Collections.sort() 를 사용할 때 전달인자가 한개이지만

Comprator의 경우에는 두개라는 점이다. 결과는 동일하다. 

출력

[Person [name=D, age=10, job=학생, score=80], Person [name=A, age=11, job=학생, score=100], Person [name=C, age=12, job=학생, score=76], Person [name=E, age=12, job=학생, score=85], Person [name=B, age=15, job=학생, score=90]]


[Person [name=D, age=10, job=학생, score=80], Person [name=A, age=11, job=학생, score=100], Person [name=C, age=12, job=학생, score=76], Person [name=E, age=12, job=학생, score=85], Person [name=B, age=15, job=학생, score=90]]

 

Comparator 익명의 내부 클래스 사용하기

Comparator의 경우, 단 한번만 재정의 해도 되는 상황이라면 익명의 내부 클래스를 사용하여 표현하면 더욱 간편하게 사용할 수 있다.

이 경우 Person 객체가 Comparator를 implements 하지 않아도 된다.

(Comparable의 경우 비교 대상이 없으므로 익명의 내부 클래스 방식으로 사용할 수 없다.)

아래와 같이 사용된다.

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;

public class SortTest {
	private static class Person{ 
		private String name;
		private int age;
		private String job;
		private int score;
		
		public Person() { }

		public Person(String name, int age, String job, int score) {
			super();
			this.name = name;
			this.age = age;
			this.job = job;
			this.score = score;
		}
	}
	
	public static void main(String[] args) {
	    ArrayList<Person> list = new ArrayList<>();
		list.add(new Person("A", 11, "학생", 100));
		list.add(new Person("B", 15, "학생", 90));
		list.add(new Person("C", 12, "학생", 76));
		list.add(new Person("D", 10, "학생", 80));
		list.add(new Person("E", 12, "학생", 85));
		
		Collections.sort(list,new Comparator<Person>() {
			@Override
			public int compare(Person o1, Person o2) {
				return o1.age-o2.age;
			}
		});
    	System.out.println(list);
    }
}


출력

[Person [name=D, age=10, job=학생, score=80], Person [name=A, age=11, job=학생, score=100], Person [name=C, age=12, job=학생, score=76], Person [name=E, age=12, job=학생, score=85], Person [name=B, age=15, job=학생, score=90]]

익명 클래스를 사용하는 경우에는 Person 클래스에 implements Comparator<Person> 을 구현하지 않고, main 함수의 Collection.sort 내에서 new 로 Comparator<Person>을 정의해 사용한다. 

이는 람다식으로 더욱 간단하게 표현될 수 있다.

람다식으로 표현하기

Collections.sort(list, (o1, o2) -> {
	return o1.score - o2.score;
});

 

Comments