들어가며
GDSC 모던 자바 인 액션 스터디 발표자료를 준비하기 위해 책을 읽어보던 도중, 책에서 Enum 비교를 위해 공통적으로 equals 메서드를 사용하는 것을 알게 되었습니다.
Enum은 == 비교가 가능하며 이에 따른 이점이 존재하므로, 강의를 진행함에 있어서 책에서 제공하는 소스 코드와 다르게 진행하게 된 이유를 말씀드리고자 합니다.
우리는 String의 문자열 내용을 비교할 때는 String의 equals 메서드를 사용합니다.
JLS, 15.21.3 Reference Equality Operators == and != 를 보면 해당 내용에 대한 설명이 잘 나와있습니다. (마지막 문단)
== 는 String 유형의 참조를 비교하는데 쓰일 수 있지만, 이러한 동등성 테스트는 두 피연산자가 동일한 String object를 참조하는지 여부를 결정합니다. 피연산자가 동일한 문자 sequence를 포함하는 경우에도 피연산자가 별개의 String object라면 결과는 false입니다.
두 문자열 s와 t의 내용은 s.equals(t) 메서드 호출을 통해 동일한지 테스트 할 수 있습니다.
참조 타입의 비교 연산은 그 위의 내용을 살펴보면 알 수 있는데, 다음과 같습니다.
equality operator의 피연산자가 둘 다 참조 타입이거나 null 타입인 경우, 연산은 객체 평등입니다.
캐스팅 변환을 통해 어느 하나의 피연산자의 형식을 다른 피연산자의 형식으로 변환할 수 없는 경우 compile-time error(컴파일 타임 오류)입니다. 두 피연산자의 런타임 값은 반드시 같지 않습니다(두 값이 모두 null인 경우 무시)
런타임에, 피연산자 값이 둘다 null이거나 둘 다 동일한 object나 배열을 참조하는 경우 true입니다. 그렇지 않으면 결과는 false입니다.
!= 의 결과는 피연산자 값이 둘다 null이거나 둘 다 동일한 object나 배열을 참조하는 경우 false입니다. 그렇지 않으면 결과는 true입니다.
본론으로 돌아와, 그렇다면 Enum Type의 경우 equals로 비교해야 할까요 == 으로 비교해야 할까요?
Enum의 equals의 내부 구현은 다음과 같습니다.
JLS 8.4.3.3 final Methods를 보면 알 수 있듯이 메서드에 final이 붙어, 하위 클래스가 재정의(overriding)하는 것을 방지하고 있습니다.
내부적으로는 equals가 == 를 사용하는 것을 알 수 있습니다.
그렇다면 == 를 사용하는 것과 equals를 사용하는 것의 차이점은 무엇일까요?
1. == 은 NullPointerException을 발생시키지 않습니다.

Ranking이라는 enum 클래스로 테스트를 진행해보겠습니다.
물론 다음과 같이 비교하면 equals에도 NullPointerException을 피할 수 있습니다.
Ranking.FIRST.equals(ranking)
2. 위에서 살펴본 것처럼, == 비교는 컴파일 타임에 타입 미스 매치를 잡아줍니다.
== 비교를 사용하면 프로그래머가 실수로 잘못된 타입 비교를 작성해도 컴파일 타임에 검사되지만 equals 메서드를 사용하면 그대로 컴파일되버립니다.
다음처럼 Ranking 타입이 아닌 Rank 타입과의 비교를 진행했을 때, 컴파일 타임에 에러가 발생하는 것을 알 수있습니다.
결론적으로, Enum을 비교할 때는 == 을 사용하는 것이 더 안전하다고 볼 수 있습니다.
출처
https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.21.3
https://docs.oracle.com/javase/specs/jls/se8/html/jls-8.html#jls-8.4.3.3