Effective Java : 아이템27. 비검사 경고를 제거하라

    들어가기 전

    이 글은 인프런 백기선님의 이펙티브 자바 강의를 복습하며 작성한 글입니다. 


    이 글의 요약

    • 비검사 경고는 컴파일러가 컴파일 환경에서 타입 안정성을 추론하는데 불안정한 데이터가 제공되면 발생한다.
    • 비검사 경고가 발생하더라도 컴파일이 완료되며 코드도 실행 가능하다. 다만 런타임 에러가 발생할 수 있다. 
    • 비검사 경고는 발생하면 가능한한 조치를 취해서 모두 제거해준다.
    • 비검사 경고 제거가 불가능할 경우, @SuppressWarnings("uncheck") 어노테이션으로 비검사 경고를 무시한다. 
      • @SuppressWarnings는 타입 안정성을 보장할 수 없지만, 실질적으로 타입 안전할 때 사용한다. 
      • @SuppressWarnings는 가능한 좁은 범위에 작성.
      • @SuppressWarnings의 이유를 작성한다. 

    핵심 정리

    • 비검사 경고(unchecked warnings)란?
      • 컴파일러가 타입 안정성을 확인하는데 필요한 정보가 충분치 않을 때 발생시키는 경고
    • 비검사 경로를 대하는 방법
      • 가능한 모든 비검사 경고를 제거하도록 조치를 취한다. 
      • 경고를 제거할 수 없지만, 안전하다고 확신한다면 @SuppressWarnings("unchecked") 어노테이션으로 경고를 숨긴다.
    • @SuppressWarnings 어노테이션 사용 방법
      • 가장 좁은 범위에 적용하는 것이 Best Practice다. 만약 변수 레벨에서 발생하는 거라면, 무조건 변수에 붙인다. (메서드 / 클래스가 아니라)
      • @SuppressWarnings("unchecked")를 무시해도 안전한 이유를 주석으로 남긴다. 

    이 글에서는 비검사 경고에 대해서 공부하고자 한다.


    비검사 경고(Unchecked Warnings)란? 

    컴파일러가 자바 코드를 컴파일 할 때는 다음 내용들을 마주칠 수 있다.

    • 컴파일 에러 (Compile Error)
      • 컴파일 에러가 발생하면, 컴파일 자체가 되지 않는다. 즉, 클래스 코드가 생성되지 않음.
    • 컴파일 경고 (Compile warnings)
      • 컴파일 경고가 발생해도 컴파일이 정상적으로 완료되며, 코드도 동작가능하다. 
      • 컴파일 경고는 문제가 발생할 수 있고, 권장하는 방법을 알려줌. 

    컴파일 경고는 여러 형태가 있을 수 있는데, 언체크 경고가 컴파일 경고 중에 하나로 포함된다. 비검사 경고는 자바의 컴파일러가 타입 안정성을 확인하는데 필요한 정보가 불충분할 때 발생하는 경고다.  아래 코드를 살펴볼 수 있다.

    public class SetExample {
    
        // Unchecked Warnings 발생
        // Set / HashSet이 모두 Raw Type으로 선언되어 있기 때문임.
        public static void main(String[] args) {
            // Unchecked 경고 발생
            Set names = new HashSet();
    
            // UnChecked 경고 발생
            Set<String> strings = new HashSet();
        }
    
    }

    컨테이너 역할을 하는 인스턴스 (Set, Collection)은 제네릭이 구현되어 있으므로 타입 매개변수를 줘서 사용하는 것이 일반적이다. 이 인스턴스가 Raw 타입을 사용하면, 인스턴스가 사용하는 타입을 컴파일러가 정확하게 추론할 수 없기 때문에 비검사 경고가 발생한다. 예를 들어 위 코드에서 names에는 String, Integer 등등이 한꺼번에 들어가서 존재할 수 있다. 

    앞서 공부한 것처럼 Raw 타입을 사용하면 안정성 / 표현력을 잃는다. 마찬가지로 컴파일러도 컴파일 과정에서 언체크 경고를 통해서 알려준다. 


    할 수 있는 한 모든 비검사 경고를 제거하라.

    비검사 경고가 발생했을 때, 가능하면 모든 조치를 취해서 비검사 경고를 제거하는 것이 좋다. 비검사 경고를 제거하면, 그만큼 안정적인 코드가 되는 것을 의미하기 때문이다. 위의 코드는 아래와 같이 타입을 선언해주면 비검사 경고를 모두 제거할 수 있게 된다. 

    비검사 경고가 발생하면, 이런 식으로 조치를 취해서 문제 코드에서 비검사 경고 표시를 삭제하자. 

    public static void main(String[] args) {
        // Unchecked 경고 발생 → 좌측에 타입 선언, 우측에 다이아몬드 연산자 추가해서 해결
        Set<String> names = new HashSet<>();
    
        // UnChecked 경고 발생 → 오른쪽에 다이아몬드 연산자 추가해서 해결
        Set<String> strings = new HashSet<>();
    }

    제거할 수 없는 경우라면 @SuppressWarnings("unchecked")를 사용

    만약 비검사 경고를 제거할 수 없는 경우라면 @SuppressWarnings를 가능한 좁은 범위에 선언해서 컴파일러가 비검사 경로를 무시하도록 유도한다. @SuppressWarnings("unchecked")는 타입 안정성을 보장할 수 있는 방법은 없지만, 실질적으로 타입 안전한 경우에만 사용해서 언체크 경고를 제거할 수 있다. 

    public class ListExample {
    
        private int size;
    
        Object[] elements;
    
        // Uncheck 경고 제거 불가능하면, 
        public <T> T[] toArray(T[] a) {
            if (a.length < size){
                /*
                왜 발생했는지 이유 작성
                 */
                @SuppressWarnings("unchecked")
                T[] result = (T[]) Arrays.copyOf(elements, size, a.getClass());
                return result;
            }
            System.arraycopy(elements, 0, a, 0, size);
            if (a.length > size)
                a[size] = null;
            return a;
        }
    
        public static void main(String[] args) {
    
        }
    }

     


    @SuppressWarnings("unchecked")는 가장 좁은 범위에 작성하라

    @SuppressWarnings는 가장 좁은 범위에 작성할 것은 권장한다. 예를 들어 변수에서 발생하는 것이라면, 가능한한 변수 영역에 작성하도록 한다. 이렇게 작성하는 이유는 경고가 발생했을 때, 내가 알고 있는 부분을 제외하고 또 타입 안정성 문제가 있을 수 있다는 것을 알려주기 때문이다. 

     


    @SuppressWarnings("unchecked")의 이유를 작성한다. 

    이 어노테이션을 사용하면, 반드시 그 경고를 무시해도 안전한 이유를 항상 주석으로 남겨야 한다. 

    댓글

    Designed by JB FACTORY