ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 자바 프로그래밍 면접 이렇게 준비한다 - (Comparable vs Comparator)
    Engineering WIKI/Book 2021. 9. 5. 11:39
    • 이력서 작성 팁
      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 비교

Designed by Tistory.