39. 명명 패턴보다 애너테이션을 사용하라
명명 패턴 이란?
메서드에 이름을 특정 이름으로 시작하게 만들어서, 해당 이름이 들어가면 실행하도록 만들기 위한 패턴
명명 패턴의 단점?
오타가 나면 안된다
public void tsetSum() { /* 오타! 테스트가 실행되지 않음 */ }
올바른 프로그램 요소에서만 사용되리라 보증할 방법이 없다
// 클래스 이름에 test를 붙여도 테스트로 인식되지 않아요 public class TestCalculator { /* ... */ }
프로그램 요소를 매개변수로 전달할 마땅한 방법이 없다
// 어떤 예외가 발생해야 테스트가 성공하는지 이름으로 표현하기 어려워요 public void testDivideByZeroThrowsException() { /* ... */ }
✅ 애너테이션을 사용하면 명명 패턴의 단점들을 개선할 수 있다!
애너테이션이란?
코드에 정보를 추가하는 특별한 표시. @로 시작한다
@Test
public void sum() { /* 테스트 코드 */ }
애너테이션의 장점
오타가 나면 컴파일 오류가 발생해요
@Tset // 컴파일 오류! 이런 애너테이션은 없어요 public void sum() { /* ... */ }
적용 위치를 제한할 수 있어요
@Target(ElementType.METHOD) // 메서드에만 사용 가능해요 public @interface Test { }
추가 정보를 전달할 수 있어요
@ExceptionTest(ArithmeticException.class) public void divideByZero() { /* ... */ }
❓ 그러면 애너테이션을 만들어서 실행시키기만 하면 되지않나?
자동으로 동작하는 건 아니다!
➔ 실제로 어떤 동작을 하게 하려면, 그 애너테이션을 해석하고 처리할 코드를 따로 만들어야 한다
간단한 애너테이션 만들기
마커 애너테이션 (정보 없이 표시만 하는 애너테이션)
// 테스트 메서드임을 표시하는 애너테이션 @Retention(RetentionPolicy.RUNTIME) // 실행 중에도 유지됨 @Target(ElementType.METHOD) // 메서드에만 사용 가능 public @interface Test { }
매개변수가 있는 애너테이션
// 특정 예외가 발생해야 성공하는 테스트를 표시 @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface ExceptionTest { Class<? extends Throwable> value(); // 매개변수 (예외 클래스) }
사용 예시
// 마커 애너테이션 사용 @Test public static void sum() { // 테스트 코드 } // 매개변수가 있는 애너테이션 사용 @ExceptionTest(ArithmeticException.class) public static void divideByZero() { int result = 5 / 0; // ArithmeticException 발생 }
여러 값을 전달하는 방법
배열 사용하기
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface ExceptionTest { Class<? extends Throwable>[] value(); // 배열 매개변수 } // 사용 예시 @ExceptionTest({ArithmeticException.class, NullPointerException.class}) public static void testMultipleExceptions() { // 이 중 하나의 예외가 발생하면 테스트 성공 }
✔️ 문법적으로 더 간단함
✔️ 모든 값을 한 번에 지정해야 함
✔️ 코드가 더 깔끔해 보일 수 있음
반복 가능한 애너테이션 사용하기 (자바 8 이상)
@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(); } // 사용 예시 @ExceptionTest(ArithmeticException.class) @ExceptionTest(NullPointerException.class) public static void testMultipleExceptions() { // 두 애너테이션을 따로 반복해서 사용 }
✔️ 각 값을 별도로 지정할 수 있음
✔️ 코드를 나중에 수정할 때 개별 항목을 추가/제거하기 쉬움
✔️ 읽기에 더 명확할 수 있음 (각 예외가 별도 줄에 표시됨)
애너테이션과 명명 패턴 비교
오타에 취약함
컴파일 시점에 오류 검사
적용 대상 제한 불가
@Target으로 적용 대상 제한 가능
추가 정보 전달 어려움
매개변수로 다양한 정보 전달 가능
패턴 확인 위해 문자열 처리 필요
리플렉션 API로 쉽게 처리 가능
실생활에서 볼 수 있는 애너테이션 예시
@Override
: 메서드가 부모 클래스의 메서드를 재정의했음을 표시
@Deprecated
: 더 이상 사용하지 않는 기능임을 표시
@SuppressWarnings
: 특정 경고를 무시하도록 지시
스프링 프레임워크: @Controller
, @Service
, @Autowired
등
요약
✔️ 명명 패턴은 오타, 적용 대상 제한, 정보 전달 문제가 있다
✔️ 애너테이션은 이러한 문제를 해결하며 더 안전하고 유연하다
✔️ 자바의 다양한 메타 애너테이션을 활용해 용도에 맞는 애너테이션을 만들 수 있다
✔️ 프로그램 요소에 정보를 추가하거나 특별한 처리가 필요할 때는 명명 패턴 대신 애너테이션을 사용하자!
🧩 어려웠던 점
리플렉션 API를 이해하고 사용하는 것이 처음에는 어려웠다
애너테이션의 다양한 메타 애너테이션(@Retention, @Target 등)의 의미 이해하기
컨테이너 애너테이션과 @Repeatable 개념 이해하기
💭 느낀 점
애너테이션은 코드를 더 명확하고 안전하게 만들어 준다
프레임워크 개발자와 사용자 간의 소통을 더 쉽게 만들어 준다
현대 자바 개발에서 애너테이션은 필수적인 기능이다
적절히 사용하면 코드의 가독성과 유지보수성이 크게 향상 될것이다
Last updated