본문 바로가기
Java

[Java] Comparable과 Comparator을 이용한 정렬

by byeongoo 2020. 7. 19.

코딩을 하다보면 컬렉션에 들어있는 객체를 정렬해야 할때가 있다. 이때 객체의 정렬 기준을 "Comparable"이나 "Comparator"를 이용해서 명시해줄 수 있다.

1. Comparable

Comparable 인터페이스는 정렬 수행 시 기본적으로 적용되는 정렬 기준이 되는 메소드를 정의하는 인터페이스이다.

Java에서 제공되는 정렬이 가능한 클래스들은 모두 Comparable 인터페이스를 구현한다. 정렬 시에 이에 맞게 정렬이 수행된다.

// Integer class
public final class Integer extends Number implements Comparable<Integer> { ... }
// String class
public final class String implements java.io.Serializable, Comparable<String>, CharSequence { ... }

(ex) Integer, Double 클래스 : 오름차순 정렬

(ex) String 클래스 : 사전순 정렬 

 

정렬할 객체에 Comparable interface를 구현하고, compareTo() 메소드를 오버라이드하여 구현한다. 

 

음수 또는 0이면 객체의 자리가 그대로 유지되고, 양수인 경우에는 두 객체의 자리가 바뀐다.

 

compareTo() 메소드는 아래와 같이 작성한다.

  • 현재 객체의 값 < 파라미터로 넘어온 객체의 값 : -1 리턴
  • 현재 객체의 값 == 파라미터로 넘어온 객체의 값 : 0리턴
  • 현재 객체의 값 > 파라미터로 넘어온 객체의 값 : 1 리턴

Point 클래스를 만들어서 오름차순과 내림 차순으로 정렬해 보겠다.

class Point implements Comparable<Point> {
    private int x;
    private int y;

    public Point(int x, int y){
        this.x = x;
        this.y = y;
    }

    @Override
    public String toString(){
        return this.x + "," + this.y;
    }

    @Override
    public int compareTo(Point p) {
        if(this.x > p.x) {
            return 1;
        } else if(this.x == p.x) {
            return 0;
        } else{
            return -1;
        }
    }
}

compareTo()를 구현했으니까 이제 main 클래스를 작성해보겠다.

public class Main {

    public static void main(String[] args) throws Exception{
        List<Point> pointList = new ArrayList<>();
        pointList.add(new Point(3, 7));
        pointList.add(new Point(1, 5));
        pointList.add(new Point(2, 4));
        Collections.sort(pointList);

        for(Point p : pointList){
            System.out.println(p.toString());
        }

    }

}

출력결과는 오름차순으로 나오는 것을 확인할 수 있다.

1, 5
2, 4
3, 7

내림 차순으로 정렬하려면 파라미터로 넘어온 값이 더 크면 그 때 1을 반환해주면 된다.

class Point implements Comparable<Point> {

    private int x;
    private int y;

    public Point(int x, int y){
        this.x = x;
        this.y = y;
    }

    @Override
    public String toString(){
        return this.x + "," + this.y;
    }

    @Override
    public int compareTo(Point p) {
        if(this.x < p.x) {
            return 1;
        } else if(this.x == p.x) {
            return 0;
        } else{
            return -1;
        }
    }
}

메인 클래스는 동일하게 유지한다.

public class Main {

    public static void main(String[] args) throws Exception{
        List<Point> pointList = new ArrayList<>();
        pointList.add(new Point(3, 7));
        pointList.add(new Point(1, 5));
        pointList.add(new Point(2, 4));
        Collections.sort(pointList);

        for(Point p : pointList){
            System.out.println(p.toString());
        }

    }

}

실행 결과 x값이 큰 순으로 내림차순으로 정렬되는 것을 확인할 수 있다.

#실행 결과
3,7
2,4
1,5

2. Comparator

Comparator 인터페이스를 직접 구현할 수 없는 경우나, 새로운 정렬 기준을 적용하고 싶다면 Comparator 인터페이스를 사용하면 된다. Arrays.sort()나 Collection.sort()의 두번째 파라미터로 넘기면 구현한 기준으로 객체를 정렬할 수 있다.

 

아래와 같이 Comparable 인터페이스를 implements 했던 코드를 수정한다.

class Point{

    private int x;
    private int y;

    public Point(int x, int y){
        this.x = x;
        this.y = y;
    }

    public int getX(){
        return this.x;
    }

    public int getY(){
       return this.y;
    }

    @Override
    public String toString(){
        return this.x + "," + this.y;
    }
}

이제 메인클래스에서 Comparator를 직접 넣어준다. 앞에 수가 더 클경우 1을 반환하므로 오름차순으로 정렬 된다.

public class Main {

    public static void main(String[] args) throws Exception{
        List<Point> pointList = new ArrayList<>();
        pointList.add(new Point(3, 7));
        pointList.add(new Point(1, 5));
        pointList.add(new Point(2, 4));
        Collections.sort(pointList, new Comparator<Point>() {
            @Override
            public int compare(Point o1, Point o2) {

                if(o1.getX() > o2.getX()){
                    return 1;
                } else if(o1.getX() == o2.getX()){
                    return 0;
                } else{
                    return -1;
                }
            }
        });

        for(Point p : pointList){
            System.out.println(p.toString());
        }

    }

}

다음은 실행 결과이다.

1,5
2,4
3,7

내림 차순으로 정렬하려면 뒤에가 더 클 경우 1을 반환하면 된다.

public class Main {

    public static void main(String[] args) throws Exception{
        List<Point> pointList = new ArrayList<>();
        pointList.add(new Point(3, 7));
        pointList.add(new Point(1, 5));
        pointList.add(new Point(2, 4));
        Collections.sort(pointList, new Comparator<Point>() {
            @Override
            public int compare(Point o1, Point o2) {

                if(o1.getX() < o2.getX()){
                    return 1;
                } else if(o1.getX() == o2.getX()){
                    return 0;
                } else{
                    return -1;
                }
            }
        });

        for(Point p : pointList){
            System.out.println(p.toString());
        }

    }

}

실행 결과

3,7
2,4
1,5

3. 람다를 이용한 정렬

람다를 사용하면 코드를 더 간결하게 짤 수 있다.

public class Main {

    public static void main(String[] args) throws Exception{
        List<Point> pointList = new ArrayList<>();
        pointList.add(new Point(3, 7));
        pointList.add(new Point(1, 5));
        pointList.add(new Point(2, 4));

        //오름차순 정렬
        Collections.sort(pointList, (a, b) -> a.getX() - b.getX());
        for(Point p : pointList){
            System.out.println(p.toString());
        }

        //내림차순 정렬
        Collections.sort(pointList, (a, b) -> b.getX() - a.getX());
        for(Point p : pointList){
            System.out.println(p.toString());
        }


    }

}

실행 결과 오름차순으로 한번 출력해주고, 내림차순으로 한번 출력해주는 것을 볼 수 있다.

1,5
2,4
3,7
3,7
2,4
1,5

오름차순 정렬시에 뒤에 나온게 앞에 나온거보다 크다면 내림차순이기 때문에 2개의 자리를 바꿔줘야한다. 그래서 그 경우에 양수를 반환한다. 내림차순으로 정렬하려면 앞에가 더 커야하므로, 뒤에가 더 클 경우 양수를 반환한다. 이것만 기억하면 헷갈리지 않고 정렬 기준을 만들 수 있다. 

'Java' 카테고리의 다른 글

[Java] Garbage Collector  (0) 2021.01.17
JVM Stack & Heap  (0) 2021.01.17
[Java] 자바 Collection  (0) 2020.06.14
[Java] 객체 값 복사 - clone() 예제  (0) 2020.05.31
[Java-source quality] Redundant Modifier  (0) 2020.05.29