이펙티브 자바 3/E_열거 타입과 애너테이션
by Gongdel
6장. 열거 타입과 애너테이션
자바에는 특수한 목적의 참조 타입이 두 가지가 있다.
- 클래스의 일종인 열거 타입(enum; 열거형)
- 인터페이스의 일종인 애너테이션(annotation)
이 타입들을 올바르게 사용하는 방법을 알아보자.
34. int 상수대신 열거 타입을 사용하라.
핵심 정리
열거 타입은 확실히 정수 상수보다 뛰어나다. 더 읽기 쉽고 안전하고 강력하다.
대다수 열거 타입이 명시적 생성자나 메서드 없이 쓰이지만, 각 상수를 특정 데이터와 연결짓거나 상수마다 다르게 동작하게 할 때는 필요하다.
드물게는 하나의 메서드가 상수별로 다르게 동작해야 할 때도 있다. 이런 열거 타입에서는 switch 문 대신 상수별 메서드 구현을 사용하자. 열거 타입 상수 일부가 같은 동작을 공유한다면 전략 열거 타입 패턴을 사용하자.
코드 34-1 정수 열거 패턴 - 상당히 취약하다.
public static final int APPLE_FUJI = 0;
public static final int APPLE_PIPPIN = 1;
코드 34-2 가장 단순한 열거 타입
public enum Apple { FUJI, PIPPIN }
35. ordinal 메서드 대신 인스턴스 필드를 사용하라.
핵심 정리
모든 열거 타입은 해당 상수가 그 열거 타입에서 몇 번쨰 위치인지를 반환하는 ordinal이라는 메서드를 제공한다.
하지만 상수 선언 순서를 바꾸는 순간 해당 메소드로 기반으로 만들어진 프로그램은 오동작할 것이다.
따라서 열거 타입 상수에 연결된 값은 ordinal 메서드로 얻지 말고, 인스턴스 필드에 저장하자.
public enum Ensemble {
SOLO(1), DUET(2), TRIO(3), QUARTET(4);
private final int numberOfMusicians;
Ensemble(int size) {
this.numberOfMusicians = size;
}
// ordinal 역할
public int getNumberOfMusicians() {
return this.numberOfMusicians;
}
}
36. 비트 필드 대신 EnumSet을 사용하라.
핵심 정리
열거할 수 있는 타입을 한데 모아 집합 형태로 사용한다고 해도 비트 필드를 사용할 이유는 없다.
EnumSet 클래스가 비트 필드 수준의 명료함과 성능을 제공하고 아이템 34에서 설명한 열거 타입의 장점까지 선사하기 때문이다.
EnumSet의 유일한 단점이라면 (자바 9까지는 아직) 불변 EnumSet을 만들 수 없다는 것이다. 그래도 향후 릴리스에서는 수정되리라 본다.
그때까지는 (명확성과 성능이 조금 희생되지만) Collections.unmodifiableSet으로 EnumSet을 감싸 사용할 수 있다.
37. ordinal 인덱싱 대신 EnumMap을 사용하라.
핵심 정리
배열의 인덱스를 얻기 위해 ordinal을 쓰는 것은 일반적으로 좋지 않으니, 대신 EnumMap을 사용하라.
다차원 관계는 EnumMap<…, EnumMap<…»으로 표현하라. ““애플리케이션 프로그래머는 Enum.ordinal을 (웬만해서는) 사용하지 말아야 한다”(아이템 35)는 일반 원칙의 특수한 사례다.
38. 확장할 수 있는 열거 타입이 필요하면 인터페이스를 사용하라.
핵심 정리
열거 타입 자체는 확장할 수 없지만, 인터페이스와 그 인터페이스를 구현하는 기본 열거 타입을 함께 사용해 같은 효과를 낼 수 있다.
이렇게 하면 클라이언트는 이 인터페이스를 구현해 자신만의 열거 타입(혹은 다른 타입)을 만들 수 있다.
그리고 API가 (기본 열거 타입을 직접 명시하지 않고) 인터페이스 기반으로 작성되었다면 기본 열거 타입의 인스턴스가 쓰이는 모든 곳을 새로 확장한 열거 타입의 인스턴스로 대체해 사용할 수 있다.
39. 명명 패턴보다 애너테이션을 사용하라.
핵심 정리
애너테이션으로 할 수 있는 일을 명명패턴으로 처리할 이유는 없다.
40. @Override 애너테이션을 일관되게 사용하라.
핵심 정리
재정의한 모든 메서드에 @Override 애너테이션을 의식적으로 달면 여러분이 실수했을 때 컴파일러가 바로 알려줄 것이다.
예외는 한 가지뿐이다. 구체 클래스에서 상위 클래스의 추상 메서드를 재정한 경우엔 이 애너테이션을 달지 않아도 된다.(단다고 해서 해로울 것도 없다.)
41. 정의하려는 것이 타입이라면 마커 인터페이스를 사용하라.
핵심 정리
마커 인터페이스와 마커 애너테이션은 각자의 쓰임이 있다. 새로 추가하는 메서드 없이 단지 타입 정의가 목적이라면 마커 인터페이스
를 선택하자.
- 클래스나 인터페이스 외의 프로그램 요소에 마킹해야 하거나,
- 애너테이션을 적극 활용하는 프레임워크의 일부로 그 마커를 편입시키고자 한다면 마커 애너테이션이 올바른 선택이다.
적용 대상이 ElementType.TYPE인 마커 애너테이션을 작성하고 있다면, 잠시 여유를 갖고 정말 애너테이션으로 구현하는 게 옳은지, 혹은 마커 인터페이스가 낫지는 않을지 곰곰이 생각해보자.
Subscribe via RSS