본문 바로가기
Engineering WIKI/Book

자바 프로그래밍 면접 이렇게 준비한다 - (Comparable vs Comparator)

by wonos 2021. 9. 5.
  • 이력서 작성 팁
    1. 팀에서 어떤 역할을 했고, 어떤 부분을 담당했으며, 무엇을 이뤄냈는지 명확하게 어필좋은 예시) 저는 'xxx' 게임의 서버 부분을 개발했습니다. 안정성에 중점을 두고 개발했으며, 첫 한 달 동안 서버가 중지되는 일 없이 일일 활성 사용자 2백만 명이 접속했습니다.
    2. 나쁜 예시) 저는 'xxx'라는 게임을 출시한 팀에서 일했습니다. 첫 한 달 동안 일일 활성 사용자가 2백만 명이 됐습니다.
  • Comparable vs Comparator
    • Comparator 인터페이스 (docs)
    • package java.lang;
      
      public interface Comparable<T> {
      	public int compareTo(T o);
      }
    • Comparable 인터페이스 (docs)
    • package java.util;
      
      @FunctionalInterface
      public interface Comparator<T> {
      	int compare(T o1, T o2);
      
      	boolean equals(Object obj);
      }
  • 일단 같은 점은 둘 다 인터페이스이고 비교에 대한 int 값을 반환한다는 점이다.패키지의 차이는 Comparable 의 사용시 import를 추가하지 않고 사용할 수 있다는 것의 의미를 넘어 java.lang 패키지에 포함되어 있다는 점에서 클래스의 public 메서드로의 의미가 강하다고 느낄 수 있다.
  • 반면 Comparator 인터페이스는 java.util 패키지에 속해서 유틸리티성 성격(비교 알고리즘) 적인 뉘앙스를 담고 있다고 볼 수 있다.
  • 차이점은 속해있는 패키지가 다르고 비교하는 메서드의 이름 및 인자가 다르다.

Comparable 인터페이스 예시

만약 Comparable 인터페이스를 통해 정렬에 대한 로직을 클래스 내부에 담고자 한다면 아래와 같이 구현해 볼 수 있을 것이다.

여기서는 ID를 오름차순으로 정렬하도록 하였다. String이 가지고 있는 compareTo를 그대로 사용하였다.

public class Person implements Comparable<Person> { // +
	private String id;
	private String name;
	private int age;
	
  // getter, setter 생략

	public Person(String id, String name,int age) {
		this.id = id;
		this.name = name;
		this.age = age;
  }
	
  @Override
	public StringtoString() {
		return "Person{" +
                "id='" + id + '\'' +
                ", name='" + name + '\'' +
                ", age=" + age +
                '}';
  }

  @Override
	public int compareTo(Person person) { 		// +
		returnthis.id.compareTo(person.id);
  }
}

정렬 후 정렬이 잘 되었는지 확인을 위한 main 함수의 수정이다.

public class CompareTest {
	public static void main(String[] args) {
	    List<Person> people = new ArrayList<Person>(3);
	    people.add(new Person("200729", "홍길동", 22));
	    people.add(new Person("211225", "김방자", 18));
	    people.add(new Person("020316", "아버지", 34));
	
	    System.out.println(people);
	    Collections.sort(people);   // +
	    System.out.println(people); // +
	}
}

[Person{id='200729', name='홍길동', age=22}, Person{id='211225', name='김방자', age=18}, Person{id='020316', name='아버지', age=34}][Person{id='020316', name='아버지', age=34}, Person{id='200729', name='홍길동', age=22}, Person{id='211225', name='김방자', age=18}]

윗줄이 입력된 순서의 출력이고, 아래는 ID 기준으로 정렬한 결과이다.

 

Comparator 인터페이스 예시

만약 ID를 오름차순이 아닌 내림차순으로 정렬을 하고 싶을때는 어떻게 할 수 있을까?

java.util 패키지의 Collections에는 reverseOrder 라는 이름의 정적 메서드가 있어서 역방향 순서의 Comparator 인터페이스를 구현한 구현체를 가지고 있다.

package java.util;

public class Collections {
// ..
	public static <T> Comparator<T>reverseOrder() {
		return (Comparator<T>) ReverseComparator.REVERSE_ORDER;
	}

	private static class ReverseComparator implements Comparator<Comparable<Object>> {

		static final ReverseComparator REVERSE_ORDER =new ReverseComparator();

		public intcompare(Comparable<Object> c1, Comparable<Object> c2) {
			return c2.compareTo(c1); // c1.compareTo(c2) 대신
    }

		private ObjectreadResolve() {return Collections.reverseOrder(); 
		}
		
    @Override
		public Comparator<Comparable<Object>> reversed() {
			return Comparator.naturalOrder();
    }
	}

따라서 아래와 같이 사용하면 반대로 내림차순으로 정렬을 할 수 있다.

public class CompareTest {
	public static void main(String[] args) {
	    List<Person> people =new ArrayList<Person>(3);
	    people.add(new Person("200729", "홍길동", 22));
	    people.add(new Person("211225", "김방자", 18));
	    people.add(new Person("020316", "아버지", 34));
	
	    System.out.println(people);
	    Collections.sort(people, Collections.reverseOrder());   // *
	    System.out.println(people); // +
	}
}

만약 ID가 아닌 이름을 기준으로 정렬을 하고 싶을 때는 어떻게 할까?

이미 구현된 compareTo를 수정해야 할까?

Comparator 인터페이스를 사용하면 비교에 대한 로직을 외부에서 주입을 받을 수 있다고 했다.

public class PersonCompareByName implements Comparator<Person> {
	@Override
	public int compare(Person person1, Person person2) {
		return person1.getName().compareTo(person2.getName());
	}
}

아래와 같이 사용이 가능하다.

public class CompareTest {
	public static void main(String[] args) {
	      List<Person> people =new ArrayList<>(3);
	      people.add(new Person("200729", "홍길동", 22));
	      people.add(new Person("211225", "김방자", 18));
	      people.add(new Person("020316", "아버지", 34));
	
	      System.out.println(people);
	      Collections.sort(people,new PersonCompareByName()); // 이름을 기준으로 정렬한다.
	      System.out.println(people);
	  }
}

 

이번에는 나이를 기준으로 정렬을 하고 싶다고 하면 아래와 같이 나이에 대한 Comparator 인터페이스의 구현을 제공하면 된다.

public class P ersonCompareByAge implements Comparator<Person> {
    @Override
		public int compare(Person person1, Person person2) {
			return Integer.compare(person1.getAge(), person2.getAge());
	  }
}

 

사용 코드

public class CompareTest {
	public static void main(String[] args) {
	      List<Person> people =new ArrayList<>(3);
	      people.add(new Person("200729", "홍길동", 22));
	      people.add(new Person("211225", "김방자", 18));
	      people.add(new Person("020316", "아버지", 34));
	
	      System.out.println(people);
	      Collections.sort(people,new PersonCompareByAge()); // 나이로 정렬
	      System.out.println(people);
	  }
}

결과

[Person{id='200729', name='홍길동', age=22}, Person{id='211225', name='김방자', age=18}, Person{id='020316', name='아버지', age=34}][Person{id='211225', name='김방자', age=18}, Person{id='200729', name='홍길동', age=22}, Person{id='020316', name='아버지', age=34}]

Reference > [Java] Comparable vs Comparator 비교