개요
개발 중 이슈가 생겨 디버깅을 하던 도중, Long 과 Long 타입을 비교하는 구문에서 서로 두 값이 동일함에도 불구하고 간헐적으로 true가 아닌 false 가 반환되는 현상을 확인하였다. 원인 확인 결과, == 연산자와 equals 의 차이에서 오는 문제였다.
원인
Java에서 객체 비교는 대표적으로 == 연산자와 equals() 메서드를 사용하여 수행할 수 있다. == 연산자는 객체의 주소값을 비교하기 때문에 같은 값을 가지고 있어도 주소값이 다르다면 false를 반환한다. 단, 위에서 언급했듯 간헐적으로 값을 정상적으로 비교할 수 있었던 이유는 Java에서 Long과 Integer의 경우 값을 -128부터 127까지의 범위에 대해 캐시하고 있기 때문에 동일한 주소의 객체로 인식하기 때문이다. 따라서 아래와 같은 현상이 발생한다.
Long a = 127L;
Long b = 127L;
Long c = 128L;
Long d = 128L;
System.out.println(a == b); // true
System.out.println(c == d); // false
System.out.println(a.equals(b)); // true
System.out.println(c.equals(d)); // true
해결
따라서, long, int 같은 Primitive타입이 아닌 Long, Integer 같은 Wrapper 타입의 값 비교는 ==이 아닌 equals를 사용하여 정확한 값 비교를 수행하도록 하자.
추가적으로, a.equals(b) 구문은 null-safe하지 않기 때문에 a와 b에 대한 null 체크가 요구된다. Java 7 부터는 Objects.equals() 를 사용할 수 있는데 해당 메서드의 경우 자체적으로 null 체크를 해주기 때문에 보다 편리한 값 비교가 가능하다. 따라서 Objects.equals(a, b) 와 같은 형태로 사용하는 방식이 가장 권장되는 방식이 되겠다.
'Dev > Java' 카테고리의 다른 글
[Effective Java : Item 12] toString을 항상 재정의하라 (0) | 2024.02.04 |
---|---|
[Effective Java : Item 4] 인스턴스화를 막으려거든 private 생성자를 사용하라 (0) | 2024.01.30 |
[Effective Java : Item 3] private 생성자나 열거 타입으로 싱글턴임을 보증하라 (1) | 2024.01.24 |
[Effective Java : Item 2] 생성자에 매개변수가 많다면 빌더를 고려하라 (1) | 2024.01.19 |
[Effective Java : Item 1] 생성자 대신 정적 팩터리 메서드를 고려하라 (2) | 2024.01.18 |