반응형
반응형

개요

 제네릭을 사용하면 많은 비검사 경고들을 마주한다. 필자의 경우 이러한 경고들은 IDE의 도움을 받아 수정했으며, 수정 자체에 큰 의의를 두진 않았다. 하지만 이러한 경고를 제거하는 것만으로 그 코드는 ClassCaseException이 발생할 일이 없는 타입 안전성을 보장하는 코드가 된다고 한다. 이제 비검사 경고를 제거하는 올바른 방법을 알아보자.

 


컴파일러의 도움을 받아 제거하라

 대부분의 경고는 컴파일러가 알려준 대로 수정하면 사라진다.

Set<Coin> coinSet = new HashSet();

 위 코드는 '매개변수화된 클래스 HashSet을 원시사용 했다.' 라는 경고가 발생한다. 매개변수화된 클래스는 제네릭 클래스를 나타낸다. 즉, 제네릭 클래스인데 타입 매개변수를 사용하지 않았다는 경고이다.

 

Set<Coin> coinSet = new HashSet<Coin>();
Set<Coin> coinSet = new HashSet<>(); // 컴파일러의 추론 기능 활용

 위와 같이 타입 매개변수를 명시하여 경고를 해결할 수도 있지만 다이아몬드 연산자(<>) 만으로 해결할 수 있다. 컴파일러가 올바른 실제 타입 매개변수를 추론해주기 때문이다.

 


경고를 제거할 수 없지만 타입 안전함이 확신된다면 경고를 숨겨라

 타입 관련 경고를 제거하려면 @SuppressWarnings("unchecked") 어노테이션 사용하면 된다. 이 어노테이션은 개별 지역변수 선언부터 클래스 전체까지 어떤 선언에도 달 수 있지만 가능한한 좁은 범위에 적용해야 한다. 보통 변수 선언, 아주 짧은 메서드, 생성자에 사용되며, 절대 클래스 전체에 적용해서는 안된다.

 

 

아래는 ArrayList의 toArray 메서드이다.

public <T> T[] toArray(T[] a) {
    if (a.length < size)
        // Make a new array of a's runtime type, but my contents:
        return (T[]) Arrays.copyOf(elementData, size, a.getClass());
    System.arraycopy(elementData, 0, a, 0, size);
    if (a.length > size)
        a[size] = null;
    return a;
}

 

 이 중 아래 코드에서 '확인되지 않는 형변환' 경고가 발생한다.

return (T[]) Arrays.copyOf(elementData, size, a.getClass());

 

return 문에는 해당 어노테이션을 적용할 수 없으므로, 아래와 같이 변수를 선언하고 어노테이션을 적용해준다. 또한 경고를 무시해도 되는 안전한 이유를 항상 주석으로 남겨둔다.

public <T> T[] toArray(T[] a) {
    if (a.length < size) {
        
        // 생성한 배열과 매개변수로 받은 배열의 타입이 모두 T[]로 같으므로 올바른 형변환이다.
        @SuppressWarnings("unchecked")
        T[] result = (T[]) Arrays.copyOf(elementData, size, a.getClass());
        return result;
    }
    System.arraycopy(elementData, 0, a, 0, size);
    if (a.length > size)
        a[size] = null;
    return a;
}

 

 


SuppressWarnings 옵션

옵션 내용
all 모든 경고
cast 캐스트 연산자 경고
dep-ann 사용하지 말아야할 주석 경고
deprecation 사용하지 말아야할 메서드 경고
fallthrough switch 문 break 누락 경고
finally 반환하지 않은 finally 블럭 경고
null null 경고
rawtypes 제네릭을 사용하는 클래스 매개변수가 불특정일때 경고
unchecked 검증되지 않은 연산자 경고
unused 사용하지 않은 코드 관련 경고

 


정리

 비검사 경고는 중요하니 무시하지 말자. 모든 비검사 경고는 런타임에 ClassCastException을 일으킬 수 있다. 경고를 없앨 방법을 찾지 못했다면, 그 코드가 타입 안전함을 증명하고 가능한 한 범위를 좁혀 @SuppressWarnings("unchecked") 어노테이션으로 경고를 숨기자. 그런 다음 경고를 숨긴 근거를 주석으로 남긴다.

반응형

+ Recent posts