06. 열거 타입과 애너테이션
#
Item 34. int 상수 대신 열거 타입을 사용하라정수 열거 패턴과 열거 타입
#
정수 열거 패턴의 단점- 다른 타입끼리 비교하더라도 컴파일러에서 경고 X (타입 안정성 X)
APPLE_PIPPIN == ORANGE_TEMPLE
이렇게 해도 경고 X
- 정수 상수는 문자열로 출력하기 까다로움
#
열거 타입 특징- 상수 하나당 자신의 인스턴스를 하나씩 만들어
public static final
필드로 공개 - 컴파일타임 타입 안정성 제공
- 각 정의별로
toString
을 가지고 있음 - 일반 클래스처럼 메서드나 필드를 추가할 수도 있음
- 상수별 메서드 구현도 가능
상수별 메서드 구현 예시
#
전략 열거 타입 패턴 예시 코드#
전략 열거 타입 패턴?다른 열거타입을 전략적으로 활용하여 중복된 구현을 다른 열거 타입에게 위임하는 것
전략 열거 타입 예시
#
열거 타입 정리- 정수 열거 패턴(상수)보단 열거 타입
- 각 상수마다 특정 데이터와 연결을 지어야하거나 다르게 동작해야할 때는 명시적 생성자나 메서드를 사용
- switch 보단 상수별 메서드 구현 (케이스 바이 케이스)
- 상수마다 같은 동작을 공유하는 패턴이 생긴다면 전략 열거 타입 패턴을 사용
- 상수의 개수는 불변일 필요 없음
#
Item 35. ordinal 메서드 대신 인스턴스 필드를 사용- 열거 타입의 상수가 몇번째 위치하는지는
ordinal()
로 알 수 있음 - 열거 타입 상수에 연결된 값은
ordinal()
메서드로 얻지말고 따로 인스턴스 필드를 추가해서 의존하자- ordinal에 의존하게 되는 함수를 만들었을경우 상수 순서가 바뀌는 순간 사이드 이펙트가 커질 수 있다
#
Item 36. 비트 필드 대신 EnumSet 을 사용하라EnumSet 예시
- EnumSet의 내부는 비트 벡터로 구현되어 있음
- 원소가 64개 이하라면 권장
- 불변 EnumSet은 만들 수가 없다는게 단점 (~ Java 9 까진 그렇다고 함)
#
Item 37. oridnal 인덱싱 대신 EnumMap을 사용하라EnumMap으로 열거타입 키를 활용하는 예시
- 배열의 인덱스를 얻기 위해 ordinal을 쓰는 것은 일반적으로 좋지 않으니, 대신 EnumMap을 사용하자
- 다차원은
EnumMap<..., EnumMap<...>>
으로 표현하자
- 다차원은
- 열거 타입을 키로 사용하도록 설계한
EnumMap
은 성능이 빠르다 - 기본 스트림에선 고유한 맵 구현체를 사용했기 때문에 EnumMap부분을 따로 추가해줘야 한다
- 코드 37-4 참고
- 코드 2개를 비교했을때 스트림을 사용하는 쪽의 코드(37-4)는 key를 덜만들 수 있음
- 37-2의 코드는 모든 Enum 타입들을 만들지만, 37-4는 해당 Enum 타입이 없을경우 키로 생성하지 않는다
#
Item 38. 확장할 수 있는 열거 타입이 필요하면 인터페이스를 사용하라- 대부분의 상황에서 열거 타입 확장을 권하진 않음
- 열거타입은 확장이 불가
- 열거타입은 인터페이스의 구현체 역할이 가능하므로 이를 이용
Operation
인터페이스를 구현한BasicOperation
,ExtendedOperation
열거 타입을 예시로 들고 있음
인터페이스 구현체인 열거 타입의 제네릭 메서드 예시
인터페이스 구현체인 열거 타입의 한정적 와일드 카드 예시
테스트 코드 2. 한정적 와일드 카드
#
Item 39. 명명 패턴보다 애너테이션을 사용하라- 명명패턴은 (JUnit3 예시)
- 오타에 예민하며
- 기대한대로 동작 안할수도 있고
- 매개변수로 전달할 마땅한 방법이 없음
- 애너테이션은 이 모든문제를 해결해줌
- 애너테이션을 적극 사용하자
- 애너테이션으로 만들 수 있다면 명명패턴은 사용하지 말자
- 도구 (프레임워크, 라이브러리) 제작자를 제외하고는 일반 프로그래머가 애너테이션 만들일은 거의 없음
- 따라서 만들어진 애너테이션을 적극 활용하자
- 물론 만드는 법도 알아두면 좋음
#
Item 40. @Override 애너테이션을 일관되게 사용하라@Override
를 일관되게 사용하면 여러가지 버그를 예방해줌- 상위 클래스의 메서드를 재정의하려는 모든 메서드에
@Overrdie
애너테이션을 달자- 상위클래스의 추상 메서드를 재정의한 경우엔 안달아도 되지만 혼동 없이 일관적으로 달자
#
Item 41. 정의하려는 것이 타입이라면 마커 인터페이스를 사용하라- 마커 인터페이스
- 아무 메서드도 담고 있지 않고, 자신을 구현하는 클래스가 특정 속성을 가짐을 표시해주기만 하는 인터페이스
- 마커 인퍼페이스가 마커 애너테이션 보다 나은 두가지
- 마커 인터페이스틑 타입의 역할을 하지만 애너테이션은 그렇지 못하다
- 적용대상을 더 정밀히 지정 가능
- 애너테이션을 대상을 클래스, 메서드 이런식으로 밖에 지정 못함
- 인터페이스는 구현, 상속을 통해 정밀하게 지정 가능
- 마커 애너테이션이 마커 인터페이스보다 나은 점
- 거대한 애너테이션 시스템의 지원을 받는다
- 마커로 등록할 대상의 객체가 매개변수로 활용된다면 마커 인터페이스로!
ElementType.TYPE
으로 마커 애너테이션을 작성하고 있다면, 시간을 두고 마커 애너테이션과 인터페이스 중 어느게 옳은지 고민하자