업무 중 BigDceimal 타입으로 된 가격을 비교하는 코드를 작성하다가 떠올라서 간단히 정리해봤다.
1. 동등 비교
두 개의 BigDecimal 값이 같은지 비교하기 위해 먼저 '==' 비교를 생각해 볼 수 있다.
BigDecimal a = BigDecimal.valueOf(100.0);
BigDecimal b = BigDecimal.valueOf(100.0);
System.out.println(a == b);
위의 코드처럼 값이 100.0으로 동일한 2개의 BigDecimal을 == 연산자로 비교했을때 출력은 어떻게 될까? 쉽게 예상할 수 있듯이 답은 false 이다. 자바에서 == 연산자를 사용한 비교는 두 객체가 동일한 객체인지를 비교하는 것이기 때문이다. 사실 BigDecimal 값이 같은지를 비교하기 위해 == 연산자를 사용해야 하는 경우는 거의 없을 것이다. 대부분의 BigDecimal을 비교하려는 목적은 두 객체가 갖고 있는 '값'이 같은지 비교하는 것이지 두 객체가 같은 객체인지를 비교하는 것이 아니기 때문이다. 따라서 BigDecimal의 값이 같은지 비교하려면 아래처럼 Object의 equals() 메서드를 사용하는 것이 올바른 방법이다.
BigDecimal a = BigDecimal.valueOf(100.0);
BigDecimal b = BigDecimal.valueOf(100.0);
System.out.println(a.equals(b)); // true
위의 코드 처럼 BigDecimal 에서 오버라이드한 equals() 메서드를 사용하여 값이 같은지를 비교할 수 있다.
2. compareTo 메서드를 활용한 크기 비교
Long 이나 Integer 등의 Wrapper 타입의 객체는 Primitive 타입 처럼 >, < 연산자를 사용하여 크기를 비교할 수 있다. 이렇게 비교할 수 있는 이유는 Wrapper 타입이 Primitive 타입으로 자동으로 형 변환이 되기 때문이다. 그러나 BigDecimal 객체는 자동 형변환이 되질 않기 때문에 >, < 연산자를 사용할 수 없다. 대신 다른 Wrapper 타입과 마찬가지로 Comparable 인터페이스를 구현하고 있기 때문에 compareTo() 메서드를 이용해 대소를 비교해야 한다.
BigDecimal a = BigDecimal.valueOf(1);
BigDecimal b = BigDecimal.valueOf(2);
int compareResult = a.compareTo(b);
if (compareResult < 0) {
System.out.println("a가 b보다 작다.");
}
if (compareResult == 0) {
System.out.println("a와 b가 같다.");
}
if (compareResult > 0) {
System.out.println("a가 b보다 크다.");
}
compareTo() 메서드 구현 스펙에 따라서 자기 자신이 비교대상보다 작으면 음수(-1)를, 같으면 0을, 크면 양수(+1)를 리턴한다. 즉 위의 코드 처럼 비교 결과인 int 값을 0과 비교하여 두 BigDecimal 객체간의 크기를 비교할 수 있다. 그러나 Primitive 타입의 크기 비교처럼 직관적이지는 않다. 이럴때는 자바에서 연산자 오버로딩을 지원하지 않는게 조금 아쉽다.
보너스 : Kotlin 에서의 BigDecimal
혹시 연산자 오버로딩을 지원하는 코틀린에서는 BigDecimal의 크기 비교를 좀 더 직관적으로 할 수 있지 않을까 생각이 들어서 찾아봤는데 역시나.. 자바보다 훨씬 간단하게 BigDecimal의 크기 비교를 할 수 있었다.
val a: BigDecimal = BigDecimal(1)
val b: BigDecimal = BigDecimal(99)
println(a == b)
println(a < b)
println(a > b)
println(a <= b)
println(a >= b)
코틀린에서는 >, <, = 연산자를 그대로 사용해서 마치 Primitive 타입 처럼 크기를 비교할 수 있다.