코딩테스트/Java 문법 정리

Comparator vs Comparable

SK_MOUSE 2022. 3. 19. 00:54
반응형

오늘은 Comparator 와 Comparable 에 대해 비교하겠다.

 

위 두 인터페이스는 아래의 생각을 밑바탕으로 사용한다.

"객체를 비교할 수 있도록 만든다."

 

# 先 정리

  Comparable Comparator
오버라이드 메소드 compareTo(T o)  compare(T o1, T o2)
비교 대상  "자기 자신과 매개변수 객체를 비교"하는 것  "두 매개변수 객체를 비교"하는 것
패키지 기본(lang에 포함되어있어서 import 필요x) java.util 에 포함되어있음.
비교 리턴 return this.age - o1.age;---- (O)
if~else로 return 양수,0,음수아무값 ----(O)
 

# Comparable 예제

class Student implements Comparable<Student> {
 
	int age;			// 나이
	int classNumber;	// 학급
	
	Student(int age, int classNumber) {
		this.age = age;
		this.classNumber = classNumber;
	}
	
	@Override
	public int compareTo(Student o) {
    /*
		// 자기자신의 age가 o의 age보다 크다면 양수
		if(this.age > o.age) {
			return 1;
		}
		// 자기 자신의 age와 o의 age가 같다면 0
		else if(this.age == o.age) {
			return 0;
		}
		// 자기 자신의 age가 o의 age보다 작다면 음수
		else {
			return -1;
		}
   */
        //아래방식이 제일 간편하다. 양수음수만 아무 값이나 반환하면 상관없다.
        
        return this.age - o.age;
	}
}
return this.age - o1.age;

를 사용하는 대신 언더플로우,오버플로우가 되지 않는 int범위 내에서 비교할것 유의!!!

 

추가로, primitive 값에 대해 위와 같은 예외를 만약 확인하기 어렵다면 <, >, == 으로 대소비교를 해주는 것이 안전하며 일반적으로 권장되는 방식이다.

 


#Comparator 예제

import java.util.Comparator;	// import 필요
class Student implements Comparator<Student> {
 
	int age;			// 나이
	int classNumber;	// 학급
	
	Student(int age, int classNumber) {
		this.age = age;
		this.classNumber = classNumber;
	}
	
	@Override
	public int compare(Student o1, Student o2) {
 
		/*
		 * 만약 o1의 classNumber가 o2의 classNumber보다 크다면 양수가 반환 될 것이고,
		 * 같다면 0을, 작다면 음수를 반환할 것이다.
		 */
		return o1.classNumber - o2.classNumber;
	}
}
a.compare(a, b); 

를 사용해도 무방하다.

즉, 객체 자체와는 상관 없이 독립적으로 매개변수로 넘겨진 두 객체를 비교하는 것이 포인트다.

Comparable과 마찬가지로 객체간 int값 비교에 오버플로우,언더플로우에 유의해야한다.

 

 

Comparator 기능만 따로 두고싶다면 어떻게 해야할까?

답은 매우 간단하다.

 

"익명 객체(클래스)를 활용한다"

Student를 비교하는 Comparator<Student>를 익명의 객체로 구현해 놓는것.

1,2 번 방식이 있는데 2번 방식이 가독성 측면에서 좋다고 한다.

import java.util.Comparator;
 
public class Test {
	public static void main(String[] args) {
    
		// 익명 객체 구현방법 1
		Comparator<Student> comp1 = new Comparator<Student>() {
			@Override
			public int compare(Student o1, Student o2) {
				return o1.classNumber - o2.classNumber;
			}
		};
	}
 
	// 익명 객체 구현 2
	public static Comparator<Student> comp2 = new Comparator<Student>() {
		@Override
		public int compare(Student o1, Student o2) {
			return o1.classNumber - o2.classNumber;
		}
	};
}
 
 
// 외부에서 익명 객체로 Comparator가 생성되기 때문에 클래스에서 Comparator을 구현 할 필요가 없어진다.
class Student {
 
	int age;			// 나이
	int classNumber;	// 학급
	
	Student(int age, int classNumber) {
		this.age = age;
		this.classNumber = classNumber;
	}
 
}

#정렬 활용

Java에서의 정렬은 특별한 정의가 되어있지 않는 한 '오름차순'을 기준으로 한다.

우리가 흔히 쓰는 Arrays.sort(), Collections.sort() 모두 오름차순을 기준으로 정렬이 된다는 것이다.

 

 

[두 수의 비교 결과에 따른 작동 방식]

 

음수일 경우 : 두 원소의 위치를 교환 안함

양수일 경우 : 두 원소의 위치를 교환 함

 

(설명)

예로들어 {1, 3, 2} 배열이 있다고 가정해보자.

return o1 - o2; 를 한다면, 1-3 = -2로 '음수'가 나올 것이다.

이 때, 자바에서는 오름차순을 디폴트 기준으로 삼고 있다고 했다. 이 말은 선행 원소가 후행 원소보다 '작다'는 뜻이다.
즉, compare 혹은 compareTo를 사용하여 객체를 비교 할 경우 음수가 나오면 두 원소의 위치를 바꾸지 않는다는 것이다.

 

 

반응형