Technology/Java

Java의 애노테이션(Annotation) 기초

ikjo 2022. 10. 9. 16:46

잠깐! 알쓸신잡, Annotation의 한글 표기법 : 애노테이션? 어노테이션?

 

자료 출처 : 국립국어원

 

※ TMI : Method → 메소드 X, 메서드 O

 

애노테이션이란?

애노테이션의 사전적인 뜻은 '주석'으로서 소스 코드의 동작에 직접적인 영향을 주지 않으면서, 메타데이터(metadata)의 한 형태로서 프로그램에 대한 정보를 제공하는데 사용된다. 이때 애노테이션은 다른 프로그램을 위한 정보로서 해당 프로그램에 미리 정의된 종류와 형식으로 작성된다.

 

Annotation vs Comment

앞서 애노테이션의 사전적인 뜻은 '주석'이라고 언급했는데, 참고로 일반적으로 우리들에게 '주석'이라고 하면 // ~  또는 /* ~ */ 와 같이 소스 코드에 대한 부연 설명을 나타내는 것(컴파일러는 이를 무시한다.)을 떠올릴 수 있다. 사실 자바에서는 이 키워드들을 Comment로서 언급하고 있는데, 사전적인 뜻으로는 주석 보다는 의견, 해설 등에 좀 더 가까운 것 같다. (하지만, 관례적으로는 이들을 주석이라고 부르는 것 같다.)

 

// ~ 와 /* ~ */ 이외에도 다음과 같이 /** ~ */을 이용하여 소스 코드 내 클래스, 필드, 메소드 등에 대한 정보를 작성할 수 있는데, 이를 Doc(Documentation) Comment라고 한다. 이때 javadoc 프로그램은 해당 내용으로부터 HTML 문서를 생성할 수 있다.

 

Test.java 소스 코드 中 Comments

 

참고로 @author, @since 등 @이 붙은 태그(Tag)들이 보이는데, 이들은 javadoc 프로그램이 특정 정보에 대해 읽어낼 수 있도록 사전에 정의된 것들이다.

 

오라클 자바 공식 문서에서는 이러한 Doc Comment 작성 방법에 대해 가이드라인을 제시하고 있는데, 관심있다면 아래 링크를 참고해보자.

 

 

How to Write Doc Comments for the Javadoc Tool | Oracle 대한민국

Javadoc Home Page This document describes the style guide, tag and image conventions we use in documentation comments for Java programs written at Java Software, Oracle. It does not rehash related material covered elsewhere: Contents Introduction Principle

www.oracle.com

 

이제는 본격적으로 애노테이션에 대해 알아보자.

 

애노테이션의 주요 용도

먼저 애노테이션의 주요 용도에는 다음과 같은 것들이 있다.

 

1. 컴파일러가 특정 오류를 감지하도록(컴파일 에러 발생 등) 하거나 경고(warnings)를 표시하지 않도록 하는 등 컴파일러에게 유용한 정보를 제공하는데 사용할 수 있다.

 

2. 컴파일 및 배포 단계에서 여러 소프트웨어 도구들이 애노테이션 정보를 처리하여 특정 소스 코드들과 XML 파일 등을 생성할 수 있다. (일부 애노테이션의 경우 실행 단계에서 처리될 수 있다.)

 

이때 애노테이션의 경우 JDK에서 기본적으로 제공하는 것(표준 및 메타 애노테이션)다른 프로그램에서 제공하는 것들이 있는데,

 

이때 JDK에서 제공하는 표준 애노테이션의 경우 java.lang.annotaion 패키지에 포함되며 주로 1번 용도와 같이 컴파일러에게 유용한 정보를 제공하는 '표준 애노테이션'으로 사용되거나 새로운 애노테이션을 정의할 때 사용하는 '메타 애노테이션'으로 사용된다.

 

다른 프로그램에서 제공하는 애노테이션의 경우 주로 2번 용도로 사용되는데, 대표적으로 Test 애노테이션(@Test)을 예시로 들 수 있겠다. Test 애노테이션은 JUnit이라는 자바를 위한 단위 테스트 프레임워크에서 제공하는 애노테이션으로서 테스트할 메서드 앞에 @Test를 붙이기만 하면 JUnit에게 테스트할 메서드를 일일이 알려주지 않아도 해당 메서드에 테스트를 해야 한다는 것을 알려줄 수 있다.(개발 생산성을 도모할 수 있다.)

 

Test 애노테이션 사용에 대한 예시

 

※ 다른 프로그램에서 제공하는 애노테이션은 다루기에 무수히 많기 때문에, 이번 글에서는 JDK에서 기본적으로 제공하는 표준 애노테이션에 대해 간략히 다루고자 하며, 메타 애노테이션 역시 표준 애노테이션과 함께 한 번에 다루기엔 내용이 방대하므로 이에 대해선 별도로 다루고자 한다.

 

표준 애노테이션

Java 8 기준 자바에서 제공하는 표준 애노테이션으로는 @Override, @Deprecated, @FunctionalInterface, @SuppressWarnings, @SafeVarargs, @Native가 있는데, 각각의 애노테이션들에 대해 간략히 살펴보자.

 

※ 참고로 @ 표시는 컴파일러에게 뒤에 나오는 것이 애노테이션임을 알려준다.

 

@Override

이전에 자바의 상속과 인터페이스를 다루면서 종종 접할 수 있었던 애노테이션으로, 상위 클래스의 메서드를 재정의하거나 인터페이스(또는 추상클래스)의 추상 메서드를 구현할 때 사용된다. 이는 용도대로 메서드 앞에만 붙일 수 있으며, 해당 메서드는 오버라이딩한 것임을 컴파일러에게 알려준다.

 

사실 @Override을 붙이지 않아도 오버라이딩하는데는 지장은 없다. 다만, 오버라이딩할 때 메서드의 이름을 잘못 작성할 경우 이는 오버라이딩이 아닌 또 다른 메서드를 정의(확장)하는 것이 되버린다. 이때 @Override을 붙여주었다면, 상위 클래스나 인터페이스에 해당 메서드(같은 이름의 메서드)가 있는지 점검해줌으로써(없으면 컴파일 에러) 개발자의 실수를 사전에 방지해줄 수 있다.

 

@Override 사용 예시

 

메서드명을 잘못 적었을 경우 컴파일 에러가 발생한다.

 

@Deprecated

새로운 버전의 JDK가 등장할 때마다 기존의 기능을 대체할 새로운 기능이 추가되곤 하는데, 기존 기능을 사용하는 많은 프로그램들이 있기에, 기존 기능을 삭제하지 않으면서도 추후에 개발자들이 새로운 기능을 사용하도록 권장할 필요성이 있다.

 

이때 @Deprecated을 기존 기능에 붙일 경우, 개발자가 해당 기능을 사용 시 컴파일러는 해당 기능은 deprecated('추천되지 않는') 되었다는 경고 메시지를 알리며(컴파일 에러는 아니다.) 개발자는 이 기능이 어떤 새로운 기능으로 대체되었다는 것을 인지할 수 있게 된다. 이러한 @Deprecate는 메서드뿐만 아니라 생성자, 속성, 패키지 등에도 적용할 수 있다.

 

Integer 클래스 中 @Deprecated 사용 예시

 

위 코드는 Integer 클래스에서 @Deprecated가 사용된 예시인데, Doc Comment의 내용과 더불어 Java 9부터 생성자를 통해 Integer 객체를 만드는 것은 권장되지 않으며, (공간 및 시간 복잡도 차원에서) 정적 팩토리 메서드(valueOf)를 통해 Integer 객체를 만들기를 권장하고 있다는 것을 알 수 있다. (Java 9부터 @Deprecated에 since 속성과 forRemoval 속성을 설정할 수 있게 되었다.)

 

 

@FunctionalInterface

함수형 인터페이스는 추상 메서드가 하나뿐이어야 한다는 제약이 있다. 이때 @FuntionalInterface를 이용하면 컴파일 에러를 통해 개발자의 실수를 사전에 방지함으로써 함수형 인터페이스를 올바르게 작성할 수 있도록 돕는다.

 

자바에서 스레드 구현 시 사용되는 Runnable 인터페이스 역시 run이라는 추상 메서드가 하나뿐인 함수형 인터페이스인데, 이 경우에도 @FuntionalInterface가 적용된 것을 볼 수 있다. 이는 사용하는 입장에서도 해당 인터페이스가 함수형 인터페이스임을 인지할 수 있게 해준다.

 

Runnable 인터페이스에 적용된 @FuntionalInterface

 

@SuppressWarnings

기본적으로 컴파일러가 경고 메시지를 나타낸다면 이를 해결해야겠지만, 때때로 이를 묵인해야 할 때도 있다. 이때 경고 메시지가 나타나는 부분에 @SuppressWarnings를 붙여주면 경고메시지가 나타나지 않도록 억제해준다.

 

경고 메시지의 종류에는 @Deprecated가 붙은 대상을 사용해서 발생하는 deprecation와 제네릭으로 타입을 지정하지 않았을 때 발생하는 unchecked 등이 있는데, @SuppressWarnings에 해당 경고 메시지의 종류를 문자열로 지정해주면 된다.

 

아래 코드에서는 이전에 deprecated된 Integer 생성자를 호출했었던 코드 앞에 @SuppressWarnings를 붙여줌으로써 컴파일 에러가 발생하지 않는 것을 확인할 수 있다.

 

@SuppressWarnings 사용 예시

 

@SafeVarargs

@SafeVarargs는 메서드에 선언된 가변인자의 타입이 제네릭이거나 매개변수화 타입일 경우 즉, non-reifiable 타입일 경우 해당 메서드의 선언부와 호출하는 부분에서 컴파일러가 발생시키는 unchecked 종류의 경고 메시지를 억제하기 위해 사용되는 애노테이션이다.

 

이 설명만 듣고서는 이 애노테이션을 정확히 언제 써야할지 감이 안 올 수도 있는데, 이에 대한 내용은 아래 글을 참고해볼 수 있다.

 

 

@SafeVarargs 언제 사용할까?

Java 5, 제네릭(generic)와 가변인자(varargs)의 등장 Java 5부터는 제네릭(Generic)과 함께 가변인자(Variable arguments, varargs라고도 함)가 등장했다. 기존 메서드의 매개변수 개수는 고정적이었지만, 가변인..

ikjo.tistory.com

 

@Native

우선 @Native를 다루기 전에 자바에서 네이티브 메서드란 무엇인지에 대해 알아보자.

 

자바에서 네이티브 메서드란 자바 프로그램에서 구현된 메서드가 아닌 JVM이 설치된 운영체제에서 구현된 메서드를 말한다. 이때 네이티브 메서드는 주로 C언어로 작성되어 있는데, 자바 프로그램에서는 단순히 해당 메서드의 선언부만 정의하고 구현은 하지 않는다.

 

예를 들어, 자바의 Thread 클래스에 정의된 currentThread, yield, sleep 메서드의 경우 아래와 같이 네이티브 메서드의 선언부가 정의되어 있다. (이외에도 더 많은 네이티브 메서드들이 있다.)

 

Thread 클래스에 정의된 네이티브 메서드(일부)

 

이처럼 네이티브 메서드는 구현부는 없지만 선언부가 자바로 정의되 있기는 하므로, 일반적인 메서드를 호출하는 것과 동일하게 호출할 수 있다. 다만, 실제 동작하는 것은 운영체제에서 구현된 메서드이다. 이때 자바에 정의된 네이티브 메서드와 운영체제의 메서드를 연결해주는 역할을 하는 것이 JNI(Java Native Interface)이다.

 

이제 다시 @Native로 돌아와서, @Native는 네이티브 메서드에 의해 참조되는 상수 필드에 붙이는 애노테이션이다. 예를 들어, String 클래스에는 2개의 byte형의 상수(LATIN1, UTF16)가 @Native와 함께 정의되어있다.

 

String 클래스 中 네이티브 메서드에 의해 참조되는 상수

 

참고자료

  • 도우출판 "자바의 정석"
  • https://docs.oracle.com/javase/tutorial/java/annotations