본문 바로가기
JAVA/[JAVA] 바구니

Comparable

by oncerun 2022. 11. 14.
반응형
  • Object.equals에 더해서 순서까지 비교할 수 있으며 Generic을 지원한다.
  • this가 compareTo에 전달된 객체보다 작으면 음수, 같으면 0, 크다면 양수를 리턴한다. 
  • 반사성, 대칭성, 추이성을 만족해야 한다.
  • 반드시 따라야 하는 것은 아니지만 x.compareTo(y)==0이라면 x.equals(y)가 true여야 한다.

 

 

 

구현 방법 

 

자연적인 순서를 제공할 클래스에 implements Comparatable <T>을 선언한다.

 

compareTo 메서드를 오버라이드 한다.

 

public class CompareNumber implements Comparable<CompareNumber>{

    @Override
    public int compareTo(CompareNumber o) {
        return 0;
    }
}

 

compareTo 메서드 안에서 기본 타입은 박싱 된 기본 타입의 compare을 사용해 비교한다.

 

 

핵심 필드가 여러 개라면 비교 순서가 중요하다. 순서를 결정하는 데 있어서 가장 중요한 필드를 비교하고 그 값이 0이라면 (같다면) 다음 필드를 비교한다.

public class CompareNumber implements Comparable<CompareNumber>{

    private int order;
    private int slotNo;

    @Override
    public int compareTo(CompareNumber o) {
        int result = Integer.compare(order, o.order);
        if (result == 0) {
            result = Integer.compare(slotNo, o.slotNo);
        }

        return result;
    }
}

기존 클래스를 확장하고 필드를 추가하는 경우 Composition을 활용할 것

 

public class CompareNumber implements Comparable<CompareNumber>{

    private int order;
    private int slotNo;

    @Override
    public int compareTo(CompareNumber o) {
        int result = Integer.compare(order, o.order);
        if (result == 0) {
            result = Integer.compare(slotNo, o.slotNo);
        }

        return result;
    }
}

public class ExtendsNumber extends CompareNumber{

    private int x, y;
}

 

부모를 비교한 후 자식을 비교한다.

public class ExtendsNumber extends CompareNumber{

    private int x, y;

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

    public static void main(String[] args) {
        ExtendsNumber extendsNumber1 = new ExtendsNumber(3, 2);
        ExtendsNumber extendsNumber2 = new ExtendsNumber(5, 2);

        TreeSet<ExtendsNumber> en = new TreeSet<>(new Comparator<ExtendsNumber>() {
            @Override
            public int compare(ExtendsNumber o1, ExtendsNumber o2) {
                int compare = Integer.compare(o1.order(), o2.order());
                if (compare == 0) {
                    compare = Integer.compare(o1.slotNo(), o2.slotNo());
                }
                if (compare == 0) {
                    compare = Integer.compare(o1.x, o2.x);
                }
                return compare;
            }
        });

        en.add(extendsNumber1);
        en.add(extendsNumber2);
    }
}

 

 

 

상속을 사용한 이후 필드를 추가하면 equals 규약이 깨진다.  그래서 그냥 상속 말고 Composition을 사용하자.

 

public class ExtendsNumber implements Comparable<ExtendsNumber>{

    private int x, y;
    private CompareNumber compareNumber;

    public ExtendsNumber(int x, int y, CompareNumber compareNumber) {
        this.x = x;
        this.y = y;
        this.compareNumber = compareNumber;
    }

    public CompareNumber compareNumber() {
        return compareNumber;
    }


    @Override
    public int compareTo(ExtendsNumber o) {
        int result = this.compareNumber.compareTo(o.compareNumber);
        if (result == 0) {
            result = Integer.compare(this.x, o.x);
        }

        return result;
    }
}

 

하지만 자바 8 버전부터는 함수형 인터페이스를 이용하여 쉽게 쉽게 짧게 가능하다.

 

COMPARATOR의 스태틱 메서드를 활용해서 Comparator 인스턴스를 쉽게 만들 수 있다.

이전에는 implements Comparable <T>을 사용했던 것과 차이점이 존재한다.

@FunctionalInterface
public interface Comparator<T> {

   public static <T, U> Comparator<T> comparing(
            Function<? super T, ? extends U> keyExtractor,
            Comparator<? super U> keyComparator)
    {
        Objects.requireNonNull(keyExtractor);
        Objects.requireNonNull(keyComparator);
        return (Comparator<T> & Serializable)
            (c1, c2) -> keyComparator.compare(keyExtractor.apply(c1),
                                              keyExtractor.apply(c2));
    }
    
 }

 

Function을 첫 번째 인자로 주고 값을 비교할 Comparator을 준다. 만약 두 번째 없다면 꺼내온 값의 naturalOrder가 적용된다.

 

public static void main(String[] args) {
    Comparator.comparing((CompareNumber c) -> c.order)
            .thenComparing(CompareNumber::getOrder)
            .thenComparing(CompareNumber::getSlotNo);
}

 

성능에 대해 고려할 때 네트워크보다 이쪽에서 병목현상이 발생한다면 직접 구현하는 걸로 바꿔서 사용해보자.

 

 

 

 

반응형

'JAVA > [JAVA] 바구니' 카테고리의 다른 글

Increasing Code Cache  (0) 2023.02.20
equals 정의  (0) 2022.11.10
finalizer와 cleaner 사용을 피하라  (0) 2022.11.07
Exception  (0) 2022.09.25
SSL/TLS 서버 통신 (JSSE, TrustManager)  (1) 2021.11.06

댓글