제네릭을 사용하면서 마주칠 수 있는 컴파일러 경고(비검사 경고)들은 다음과 같다.
이 중 비검사 경고는 제일 쉽게 제거 가능하기 때문에, 할 수 있는 한 모든 비검사 경고를 제거하는 것이 좋다.
비검사 경고, 비검사 메서드 호출 경고, 비검사 매개변수화 가변인수 타입 경고, 비검사 변환 경고 등..
Set<Lark> exaltation = new HashSet();
javac 명령줄 인수에 -Xlint:uncheck
옵션을 추가하면은 컴파일러가 어디가 잘못되었는지 알려준다.
Venery.java:4: warning: [unchecked] unchecked conversion Set exaltation = new HashSet();
required: Set
found: HashSet
참고로, 자바 7에서부터 지원하는 다이아몬드 연산자( <>
)을 사용하면 컴파일러가 올바른 실제 타입 매개변수를 추론해주기 때문에 직접 타입 매개변수를 명시하지 않아도 된다.
Set<Lark> exaltation = new HashSet<>();
경고를 제거할 수는 없지만, 타입이 안전하다고 확신할 수 있다면 @SuppressWarnings("unchecked")
어노테이션을 통해 경고를 숨길 수 있다.
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.SOURCE)
public @interface SuppressWarnings {
String[] value();
}
@Target
에서 볼 수 있듯이 거의 모든 곳에 붙일 수 있지만 가능한 한 좁은 범위에 적용하는 것이 좋다. 타입 안전성을 검증하지 않았다면, 경고 없이 컴파일 되지만 런타임에는 여전히 ClassCastException
을 던지기 때문이다.
만약 한줄이 넘는 메서드나 생성자에 달렸다면, 아래의 예제와 같이 지역변수 선언 쪽으로 옮기는 것을 권장한다.
public <T> T[] to Array(T[] a) {
if(a.length < size)
return (T[]) Arrays.copyOf(elements, size, a.getClass());
...
}
해당 코드를 컴파일하면 다음과 경고가 발생한다.
지역변수를 추가하여, @SuppressWarnings
의 범위를 좁힐 수 있다.
public <T> T[] to Array(T[] a){
if(a.length < size) {
@SupressWarnings("unchecked")
T[] result = (T[]) Arrays.copyOf(elements, 0, a, 0, size);
return result;
}
}
마지막으로, 해당 어노테이션을 사용할 때면 그 경고를 무시해도 안전한 이유를 항상 주석으로 남겨야 한다. 다른 사람이 코드를 이해하는데 도움이 되며, 코드를 잘못 수정하여 타입 안전성을 잃는 상황을 줄여주기 때문이다.