Java

Effective Java 제 6장 - 열거 타입과 애너테이션

iksadnorth 2023. 8. 22. 23:05

해당 게시물은 책 'Effective Java'를 참고하고 작성했습니다.

 

Enum 타입의 ordinal 메서드는 가급적 사용하지 말기!
이는 클래스 소스 코드 내의 열거 타입 순서가 바뀌면 변경되기에 지양해야 한다.

비트 필드 대신 EnumSet을 사용해라!
비트 필드란 Enum 타입을 사용할 때, 라디오 버튼마냥 1개만 선택하는 한계를 해결하기 위해
체크 박스처럼 다중 선택을 위해 첫 항목을 (0001), 두번째를 (0010), 셋째는 (0100), ... 등등으로 설정해 
(0101)라고 입력하면 첫 번째와 세번째 항목을 입력했다는 것을 인지하기 위해 사용한다.
이 방식은 위에서 언급한 ordinal 처럼 소스코드 순서에 너무 의존하기 때문에 사용한다.
때문에 차라리 Set<EnumType>을 이용하는 것이 낫다.

열거 타입을 확장하고 싶다면 인터페이스를 사용해라!
열거 타입은 대부분의 경우에선 완벽하지만 확장할 수 없다는 단점이 있다.
이는 OCP를 지키기 어렵게 하고 때문에 버그를 발생시킬 확률을 높인다.
때문에 이런 확장 문제를 해결할 만한 방법으로서 인터페이스를 활용하면 된다.

더보기
// API
public interface Operation {
    double apply(double x, double y);
}
public enum BasicOperation implements Operation {
    PLUS("+") {
        public double apply(double x, double y) { return x + y; }
    }
}
public enum ExtendedOperation implements Operation {
    EXP("^") {
        public double apply(double x, double y) { return Math.pow(x, y) }
    }
}

// 클라이언트
// <T extends Enum<T> & Operation> 타입의 Enum 클래스를 모두 받을 수 있다.
public <T extends Enum<T> & Operation> void use(Class<T> opEnumType, double x, double y) {
    for(Operation op : opEnumType.getEnumConstants()) {
        op.apply(x, y);
    }
}

명명 패턴보다 애너테이션을 사용하라!
어떤 메서드를 구분짓기 위해 명명패턴을 설정하는 것보다 @Annotation을 이용하는 것이 휠씬 좋다. 
예를 들어, 구 버전의 JUnit에서는 Test 메서드를 인지하기 위해 메서드명의 접두사를 Test로 설정했어야 했다.

void testSafety() {}

하지만 JUnit 4부터 @Annotation을 이용해서 Test 메서드를 구분 짓기 시작하면서 메서드 명명 규칙을 지키지 않아도 된다. 이는 오타로 인한 에러를 줄일 수 있기에 보다 안전한 개발을 이어나갈 수 있다.

@Test
void safety() {}

@Override 어노테이션을 일관되게 사용하자!
@Override 어노테이션은 실수로 매개변수를 잘못 기입해서 overload되는 것을 막는다.

예를 들어, Object.equals()를 재정의하는 코드가 있다고 치자

public boolean equals(Bigram b) {
    return b.first == this.first;
}

@Override를 사용하지 않아도 재정의는 되기 때문에 문제가 없을 것 같지만,
사실 Object.equals(Bigram b)가 아니라 Object.equals(Object o)라고 시그니처를 정해야 했었다.
만약 @Override를 기입했다면 컴파일 당시에 오류를 일으켜서 문제를 수정했을 것이다. 하지만 그렇지 못해
단순히 overload가 되었을 뿐이다.

특정 매서드의 속성을 정의하기 위해서라면 마커 인터페이스보다 마커 어노테이션을 사용하자!
Serializable과 같이 직렬화가 가능한 클래스의 속성을 표현하기 위해서만 존재하는 인터페이스를 마커 인터페이스라고 한다. 이는 부작용이 많기 때문에 차라리 마커 어노테이션으로 확인하는 것이 좋다.