[Effective Java 3/e] 아이템 39 - 확장할 수 있는 열거 타입이 필요하면 인터페이스를 사용하라


아이템 39 - 명명 패턴보다 애너테이션을 사용하라

명명 패턴의 단점 - (ex -Junit의 경우 test로 시작)

  • 오타가 나면 안된다.
  • 올바른 프로그램 요소에서만 사용되지 않을 수 있다.
  • 프로그램 요소를 매개변수로 전달할 방법이 없다.
    • 예외를 던져야 성공하는 테스트의 경우 기대하는 에외 타입을 테스트에 매개변수로 전달하기 어려움

마커(marker) 애너테이션 타입 선언

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Test {}

public class Sample {
  @Test public static void m1() {}
}

매개변수 하나를 받는 애너테이션 타입

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface ExceptionTest {
  Class<? extends Throwable> value();
}

public class Sample {
  @ExceptionTest(ArithmeticException.class)
  public static void m1() {
    int i = 0;
    i = i / i;
  }
}

배열 매개변수를 받는 애너테이션 타입

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface ExceptionTest {
  Class<? extends Throwable>[] value();
}

public class Sample {
  @ExceptionTest({ IndexOutOfBoundsException.class, NullPointerException.class })
  public static void m1() {
    List<String> list = new ArrayList<>();
    list.addAll(5, null);
  }
}

반복 가능 애너테이션을 두 번 단 코드

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Repeatable(ExceptionTestContainer.class)
public @interface ExceptionTest {
  Class<? extends Throwable> value();
}

// 컨테이너 애너테이션
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface ExceptionTestContainer {
  ExceptionTest[] value();
}

public class Sample {
  @ExceptionTest(IndexOutOfBoundsException.class)
  @ExceptionTest(NullPointerException.class)
  public static void m1() {}
}

정리

  • 애너테이션으로 할 수 있는 일을 명명 패턴으로 할 이유는 없다.
  • 자바 프로그래머라면 자바가 제공하는 애너테이션 타입들은 사용해야 한다.