J2SE 5.0에는 새로운 언어 기능이 다수 도입되었는데, 여기에는 제네릭(Generics)과 향상된 루프문(Enhanced for Loop)이 포함된다. 제네릭(GENERIC)과 향상된 루프문에 대해서는 이미 이전 테크 팁에서 살펴본 바 있다. J2SE 5.0에 추가된 또 다른 중요한 기능으로 주석을 들 수 있으며, 본 팁에서는 J2SE 5.0에 내장된 주석을 살펴보기로 한다.
먼저, 주석이란 무엇인가? JSR 175: A Metadata Facility for the Java Programming Language의 일부로 정의된 주석은 메타데이터를 프로그램 엘리먼트(클래스, 인터페이스, 메소드 등)에 연결하는 방법을 제시해준다. 주석은 해당 엘리먼트에 대해 생성된 바이트코드를 변경하지 않는 추가 수식자(modifier)라고 할 수 있다.
메타데이터를 소스 코드에 도입한다는 개념은 J2SE 5.0에서 처음 등장한 것은 아니다. 사용자가 @deprecated
태그를 메소드의 javadoc 코멘트에 추가하면 컴파일러는 이를 메소드에 관한 메타데이터로 취급하는데, 이런 기능은 J2SE의 1.0 버전부터 포함되었다. 초기 버전의 플랫폼의 경우 이미 System
의 getenv()
메소드(1.1 addendum까지는 Java Language Specification에 포함되어 있지 않았음)와 더불어 구(deprecated) 메소드가 포함되어 있었지만, 현재로서는--적어도 구문의 @
부분에 관한 한--개념은 거의 동일하다고 볼 수 있다. 단, 위치에는 변동 사항이 생겼다는 점을 알아두기 바란다--주석 태그가 코멘트가 아니라 소스에 포함된다. 여기서 주안점은 주석이 선언적 프로그래밍 모델을 체계적으로 지원하기 위한 방법이라는 사실이다.
이제 J2SE 5.0에 포함된 최초의 주석, @Deprecated
부터 살펴보도록 하자. 우선 여기서는 대문자 D에 유의할 필요가 있다. 기능적으로 볼 때, 소스 내의 @Deprecated
는 클래스 또는 메소드와 연결된 javadoc 내의 @deprecated
와 동일하게 작동한다. 메소드에 @Deprecated
태그를 플래그하면 해당 메소드나 클래스 사용 시 사용자에게 경고 메시지를 보내도록 컴파일러를 환기시키는 효과가 있다.
아래의 Main
클래스는 @Deprecated
주석과 @deprecated
코멘트가 플래그된 deprecatedMethod()
라는 이름의 메소드를 가진다.
/**
* @deprecated Out of date. Use System.foobar() instead.
*/
@Deprecated
public static void deprecatedMethod() {
System.out.println("Don't call me");
}
}
주석이 붙은 클래스도 주석이 붙지 않은 경우와 동일한 방식으로 컴파일한다.
> javac Main.java예상대로 Main.class
가 생성된다.
deprecated 메소드를 사용하면 javadoc 내의 @deprecated
태그를 사용할 때와 마찬가지로 컴파일 시간 경고가 생성된다. 관련 예는 다음과 같다.
public static void main(String args[]) {
Main.deprecatedMethod();
}
}
아래의 클래스를 컴파일하면,
> javac User.javadeprecated 메소드를 사용하는 데 대한 경고 메시지가 다음과 같이 표시된다.
Note: User.java uses or overrides a deprecated API.Note: Recompile with -Xlint:deprecation for details.
컴파일 라인에 -Xlint
를 추가하면 무엇이 잘못되었는지 구체적으로 표시할 수 있다.
User.java:3: warning: [deprecation] deprecatedMethod() in
Main has been deprecated
Main.deprecatedMethod();
^
1 warning
@deprecated
코멘트에서 @Deprecated
주석으로 변경되더라도 시스템에는 아무런 변화가 생기지 않으며, 단지 작업 수행 방식에 약간의 변화가 발생하는 것 뿐이다. 하지만 J2SE 5.0 플랫폼에 새로 추가된 다른 두 개의 주석, @Override
와 @SuppressWarnings
의 경우에는 플랫폼에 새로운 기능을 부여할 수 있다.
@Override
주석은 메소드 선언과 함께 사용할 수 있는데, 이름에서 알 수 있듯이 @Override
주석을 사용하여 수퍼클래스의 메소드를 오버라이드하도록 되어 있는 메소드를 플래그한다. 이 주석은 왜 사용하는 것일까? 오류를 더 신속하게 잡아내기 위해서이다. 아마도 여러분은 메소드를 오버라이드하려다가 메소드 이름의 철자를 틀리거나, 잘못된 인자를 지정하거나, 다른 리턴 타입을 설정했던 적이 무수히 많았을 것이다. 즉, 원래의 의도는 기존의 메소드를 오버라이드하는 것이었는데 그만 새로운 메소드를 정의해 버리는 결과가 종종 발생하게 되는 것이다. @Override
를 이용하면 그나마 클래스에서 문제점을 빨리 발견할 수가 있다.
@Override
public int hashcode() {
return 0;
}
@Override
public boolean equals(Object o) {
return true;
}
}
여기서 문제는 메소드 이름이 hashcode
가 아니라 hashCode
여야 한다는 점이다. 메소드 선언이 훨씬 더 큰 클래스 정의를 위해 소스에 묻혀 버린다고 가정해보자. 최초의 @Override
주석이 없다면, hashCode()
메소드(모두 소문자가 아니라, 대문자로 시작되는 두개의 영단어를 붙여 써서)가 호출되는 대신 상위 Object
클래스의 기본값 동작을 얻고 있다는 사실을 알아차리는 데 얼마나 많은 시간이 걸리겠는가? 하지만 이제는 @Override
주석 덕분에, 클래스 컴파일 시 컴파일 시간 오류가 생성되어 문제점을 경고할 수 있다.
Overrode.java:2: method does not override a method from its
superclass
@Override
^
1 error
이런 특성의 오류를 좀더 빨리 발견할 수만 있다면 수정에 드는 수고와 비용을 획기적으로 절감할 수 있을 것이다. hashCode()
메소드의 경우 절대로 상수를 리턴해서는 안된다는 점에 유의할 것. hashCode()
와 equals()
의 올바른 사용법에 관한 자세한 설명을 보려면 Joshua Bloch가 저술한 Effective Java Programming Language Guide(영문)의 8항을 참조할 것.
J2SE 5.0에 새로 추가된 주석의 마지막 @SuppressWarnings
는 그 중에서도 가장 흥미롭다고 할 수 있다. 이 주석은 일반적으로 경고하는 내용을 경고하지 말도록 컴파일러에게 지시하는데, 경고는 일종의 범주에 속하므로 주석에 대해 어떤 종류의 경고를 금지할 것인지 지시해야 한다. javac 컴파일러는 all, deprecation, unchecked, fallthrough, path, serial, finally 등 7개의 금지 옵션을 정의한다. (언어 스펙은 이 중에서 두 가지-- deprecation과 unchecked--만을 정의함.)
예시를 위해 fallthrough 옵션 금지사항에 대해 살펴보기로 한다. 먼저 아래의 클래스를 사용해보자. 클래스에는 switch
문의 각 케이스에 대한 break
문이 빠져 있다는 점에 유의할 것.
public static void main(String args[]) {
int i = args.length;
switch (i) {
case 0: System.out.println("0");
case 1: System.out.println("1");
case 2: System.out.println("2");
case 3: System.out.println("3");
default: System.out.println("Default");
}
}
}
javac으로 클래스를 컴파일하면 단순히 .class
파일만 생성되고 경고는 표시되지 않는다는 것을 알 수 있다.
컴파일러가 fall through하는(즉, 하나 이상의 break
문이 빠져 있는) switch
문에 관해 경고하기를 원할 경우에는 -Xlint:fallthrough
옵션으로 컴파일한다.
그러면 아래의 경고문이 생성된다.
Fall.java:6: warning: [fallthrough] possible fall-through into casecase 1: System.out.println("1");
^
Fall.java:7: warning: [fallthrough] possible fall-through into case
case 2: System.out.println("2");
^
Fall.java:8: warning: [fallthrough] possible fall-through into case
case 3: System.out.println("3");
^
Fall.java:9: warning: [fallthrough] possible fall-through into case
default : System.out.println("Default");
^
4 warnings
그러나 switch
문에 각 케이스에 대한 break
문이 빠져 있다는 사실을 무시하고 싶은 경우에는 어떻게 해야 할까? 바로 이 때 @SuppressWarnings
주석이 필요하다. main()
메소드 선언 앞에 다음 행을 추가하면,
-Xlint:fallthrough
옵션으로 클래스를 컴파일할 경우,
.class
파일만 생성되고 경고문은 표시되지 않는다.
@SuppressWarnings
주석은 또한 컬렉션 엘리먼트의 데이터 유형을 지정하지 않고 컬렉션을 사용할 경우에 표시되는 것과 같은 그 밖의 경고를 금지하는 데도 사용될 수 있다. 그러나 단순히 컴파일 시간 경고를 피하기 위해서 @SuppressWarnings
주석을 사용해서는 안 된다. 제네릭을 염두에 두지 않고 구축된 라이브러리를 사용할 때처럼, 금지되지 않은 경고가 불가피한 경우에 이 주석을 사용하도록 한다.
이것으로 내장 주석 기능에 관한 설명은 마무리하고, 마지막으로 (인자를 포함한) 주석은 통상적으로 하나의 행에서 독자적으로 지정된다는 점에 유의하기 바란다.
J2SE 5.0에 이미 정의되어 있는 주석을 사용하는 것 보다 사용자가 직접 주석을 정의하는 경우에는 더 많은 기능들을 활용할 수 있다. 주석 정의에 관한 자세한 내용은 Annotations(영문)를 참조하기 바란다.
<출처 - http://kr.sun.com/developers/techtips/2006/c0713.html >