728x90
39. 명명 패턴보다 애너테이션을 사용하라
명명 패턴의 단점
- 오타가 나면 안 된다.
- 올바른 프로그램 요소에서만 사용된다는 보장이 없다.
- 프로그램 요소를 매개변수로 전달할 마땅한 방법이 없다.
애너테이션 선언
- 일반적인 정의 방법
public @interface Sample {
}
- JUnit에서 사용하는 @Test 애너테이션
@Target({ ElementType.ANNOTATION_TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@API(status = STABLE, since = "5.0")
@Testable
public @interface Test {
}
메타 애너테이션
- 애너테이션 선언에 다는 애너테이션
@Retention
- 애너테이션이 언제까지 남아 있을지 결정하는 것으로, 일종의 라이프 사이클에 대한 정의
- RetentionPolicy.SOURCE
- 소스코드(.java)에 남아 있으며, 컴파일 과정에서 해당 정보가 사라진다.
- Lombok의 @Getter, @Setter
@Target({ElementType.FIELD, ElementType.TYPE})
@Retention(RetentionPolicy.SOURCE)
public @interface Getter {
//...
}
- RetentionPolicy.CLASS
- 클래스 파일(.class), 바이트 코드에 남아 있으며, 런타임 시에는 유지되지 않는다.
- Lombok의 @NonNull
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.LOCAL_VARIABLE, ElementType.TYPE_USE})
@Retention(RetentionPolicy.CLASS)
@Documented
public @interface NonNull {
}
- RetentionPolicy.RUNTIME
- 런타임까지 남아있어서, Reflection으로도 정보 조회가 가능하다.
- Spring의 @Controller, @Service, @Autowired
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Controller {
/**
* The value may indicate a suggestion for a logical component name,
* to be turned into a Spring bean in case of an autodetected component.
* @return the suggested component name, if any (or empty String otherwise)
*/
@AliasFor(annotation = Component.class)
String value() default "";
}
@Target
- 어느 선언부에서 사용되어야 하는지를 명시
- java.lang.annotation.ElementType enum에 명시된 내용을 바탕으로 적용 범위 지정 가능
package java.lang.annotation;
public enum ElementType {
TYPE, // 클래스, 인터페이스, Enum 선언시
FIELD, // 멤버 변수 선언시
METHOD, // 메서드 선언시
PARAMETER, // 매개변수 선언시
CONSTRUCTOR, // 생성자 선언시
LOCAL_VARIABLE, // 지역 변수 선언시
ANNOTATION_TYPE, // 애너테이션 선언시
PACKAGE, // 패키지 선언시
TYPE_PARAMETER, // 매개 변수 타입 선언시
TYPE_USE, // 타입 사용시
MODULE; // 모듈 선언시
private ElementType() {
}
}
@Documented
- 문서에도 애너테이션 정보 표시
@Inherited
- 자식 클래스가 애너테이션 상속 가능
@Repeatable
- 반복적으로 애너테이션 선언 가능
- @Repeatable을 달게 되면, 이를 반환하는 컨테이너 애너테이션이 필요하다.
- 컨테이너 애너테이션은 내부 애너테이션 타입의 배열을 반환하는 value 메서드를 정의해야 한다.
- 컨테이너 애너테이션 타입에는 @Retention과 @Target을 명시해야 한다.
마커 애너테이션
- 아무 매개변수 없이, 단순히 대상에 마킹하는 용도
- 이름에 오타를 내거나, 메서드 선언 외의 프로그램 요소에 달면 컴파일 에러 발생
Reference
40. @Override 애너테이션을 일관되게 사용하라
상위 클래스의 메서드를 재정의하려는 모든 메서드에 @Override를 달아야 한다.
- 해당 애너테이션은, 상위 타입의 메서드를 재정의했음을 의미한다.
- 명시적으로 Overriding을 나타낸다.
- IDE에서 Overriding이 잘 됐는지 아닌지도 사전에 알 수 있어 일관적으로 사용해주는 것이 좋다.
- 클래스뿐 아니라 인터페이스의 메서드를 재정의할 때도 사용할 수 있다.
- 추상 클래스나 인터페이스에서는 상위 클래스, 인터페이스의 메서드를 재정의하려는 모든 메서드에 달자.
41. 정의하려는 것이 타입이라면 마커 인터페이스를 사용하라
마커 인터페이스(Marker Interface)
- 어떠한 메서드도 없으면서, 자신을 구현하려는 클래스가 특정 속성을 가짐을 표시해주는 인터페이스
- Serializable
package java.io;
// 이 인터페이스가 있으면 직렬화가 가능함을 의미한다.
public interface Serializable {
}
마커 인터페이스 vs 마커 애너테이션
- 마커 인터페이스가 마커 애너테이션보다 나은 점
- 마커 인터페이스를 구현한 클래스의 인스턴스들을 구분하는 타입으로 사용할 수 있다.
- 적용 대상을 좀 더 정밀하게 지정할 수 있다.
- 마커 애너테이션이 마커 인터페이스보다 나은 점
- 애너테이션 시스템의 지원을 받는다.
둘 중 어떤 것을 어떻게 사용하는 것이 좋은가?
- 클래스와 인터페이스 외의 프로그램 요소를 마킹하는 경우는 당연히 애너테이션을 쓴다.
- 당연한 이야기지만, 일관성을 위해서 애너테이션을 적극적으로 활용하는 프레임워크를 쓴다면, 애너테이션을 쓴다.
- 마킹된 객체를 매개변수로 받는 메서드를 작성할 일이 있다면, 마커 인터페이스를 쓴다.
- 적용 대상이 ElementType.TYPE인 마커 애너테이션에 대해서는 한 번쯤 마커 인터페이스가 될 수 있는지 고민하자.
Reference
728x90
'책, 세미나, 컨퍼런스 후기 > 2022' 카테고리의 다른 글
Effective Java 3/E - 6장 열거 타입과 애너테이션 - 1 (0) | 2022.02.27 |
---|---|
Effective Java 3/E - 5장 제네릭 - 2 (0) | 2022.02.13 |
Effective Java 3/E - 5장 제네릭 - 1 (0) | 2022.02.05 |
Effective Java 3/E - 4장 클래스와 인터페이스 - 3 (0) | 2022.02.01 |
Effective Java 3/E - 4장 클래스와 인터페이스 - 2 (0) | 2022.01.23 |