본문 바로가기
Java

[Java] Enum을 비교해 보자

by kriorsen 2024. 4. 15.

Java의 값 비교 방식

자바에서 일반적으로 참조형 객체는 equals() 메서드를, 원시형(primitive type)은 == 연산자를 이용해 비교한다.

 

1. equals() 메서드

equals()는 Object 클래스의 메서드이며 내부적으로는 == 연산자와 동일하게 주소값 비교를 수행한다.

Object의 equals() 정의

String 클래스와 같은 경우, 메서드 오버라이딩을 통해 문자열 간 비교가 가능해 동등성을 검증할 수 있다.

 

2. == 연산자

== 연산자의 경우 주소값을 비교하기에 객체의 동일성을 검증하는 방식에 해당된다. 원시 타입의 경우 값 비교가 가능하지만, 참조 타입에 대해서는 동등성이 아닌 동일성을 비교한다.

 

Enum 비교 방식

Enum은 원시 타입이 아니지만, 싱글톤이라는 특징이 있다. 즉, 자바에서 Enum의 인스턴스는 유일한 주소를 가진다. 때문에 String과 같은 클래스와 다르게 == 연산자를 이용한 비교만으로도 동등성을 검증할 수 있다. 애초에 Enum 내부적으로도 == 을 이용한 비교를 수행하고 있다.

Enum의 equals() 정의

 

그렇다면 euqals() 메서드 대신 == 연산자를 사용했을 때 어떤 장점이 있을까?

 

1. NullPointerException이 발생하지 않는다

equals()는 메서드이기 때문에, 해당 메서드가 호출될 시에는 인스턴스가 실제로 존재하고 있다는 것을 전제로 둔다. 그리고 이 전제가 성립하지 않았을 때 NullPointerException이 발생하게 된다. 

public class EnumTest {
    @DisplayName("equals() 비교 시 NullPointerException이 발생한다.")
    @Test
    void test1() {
        Shape shape = null;
        assertThatThrownBy(() -> shape.equals(Shape.CLOVER))
                .isInstanceOf(NullPointerException.class);
    }

    @DisplayName("== 비교 시 NullPointerException이 발생하지 않는다.")
    @Test
    void test2() {
        Shape shape = null;
        assertThatCode(() -> {
            boolean result = shape == Shape.CLOVER;
        }).doesNotThrowAnyException();
    }
}

 

실행 결과에서 볼 수 있듯 비교 연산자를 통한 비교에서는 NullPointerException을 예방할 수 있다.

 

2. 타입 안정성

또 다른 이유로 == 연산자를 통한 비교는 비교 시에 타입 안정성을 강제한다.

 

 

인텔리제이에서 실행 전부터 빨간 줄이 뜨고 컴파일 시점에 오류가 발생해서 빌드에 실패한다.

 

반면 equals()의 경우에는 Shape와 Number Enum을 비교해도 컴파일 오류가 발생하지 않는다.

 

 

결론

타입 안정성 보장과 NullPointerException의 예방을 위해 Enum 비교에는 equals() 대신 == 연산자를 사용하자.