Skip to content

Latest commit

 

History

History
109 lines (69 loc) · 6.12 KB

비검사_경고를_제거하라(강철원).md

File metadata and controls

109 lines (69 loc) · 6.12 KB

🚀 Item 27 비검사 경고를 제거하라

자바 프로그래밍에서 타입 안정성을 확보하고 실행 시간에 발생할 수 있는 예기치 못한 ClassCastException과 같은 오류를 방지하기 위해 제네릭을 사용합니다. 제네릭은 컴파일 시점에 타입 체크를 가능하게 하여, 더욱 안정적인 코드를 작성할 수 있도록 도와줍니다. 그러나 제네릭을 사용하면서 종종 마주치는 문제가 있습니다. 바로 '비검사 경고(unchecked warnings)'입니다. 이펙티브 자바의 아이템 27에서는 이러한 경고를 가능한 제거하라고 조언하고 있습니다. 그 이유와 방법에 대해 자세히 알아보겠습니다.

❓ 비검사 경고란?

비검사 경고를 제거라는 이유를 알기전에 비검사 경고가 무엇인지부터 알아야합니다.
비검사 경고는 컴파일러가 타입 안정성을 확인하는데 필요한 정보가 충분치 않을 때 발생시키는 경고입니다.

예를들어 봅시다. 우리가 쇼핑 리스트를 만들다고 가정해봅시다. 이 리스트에는 사과, 바나나, 책, 연필등 다양한 것들이 담길 수 있습니다. 여기서 자바는 리스트에 무엇이 들어갈지 미리 알고 싶어 합니다. 과일만 담긴 리스트인지 아니면 학용품이 담긴 리스트인지등 알고싶어합니다.

실제코드로 비유하자면 String이 들어갔는지 사용자 정의 클래스 타입이 들어갔는지 Integer이 들어갔는지등 자바는 미리 알고싶어합니다. 하지만 raw 타입을 사용하면 미리 어떤 타입이 들어갔는지 알 수 없기 때문에 비검사 경고를 발생시킵니다.

경고 제거의 중요성

경고를 제거하는 것은 단순히 깔끔한 코드를 유지하는 것 이상의 의미가 있습니다. 경고를 제거함으로써 코드의 타입 안정성을 강화하고, 잠재적인 오류 가능성을 줄여, 유지 보수가 쉽고 안정적인 소프트웨어를 개발할 수 있습니다.

비검사 경고를 제거하는 방법

  1. 제네릭 타입 명시: 컬렉션을 사용할 때 가능한 한 구체적인 제네릭 타입을 명시합니다. 예를 들어, List list = new ArrayList(); 대신 List<String> list = new ArrayList<>();와 같이 사용합니다.

  2. 메서드에 제네릭 사용: 메서드 반환 타입이나 파라미터에 제네릭을 사용하여, 메서드의 사용이 더 명확하고 안전하도록 합니다.

  3. @SuppressWarnings 애너테이션 제한적 사용: 때로는 경고를 제거할 수 없는 상황이 발생합니다. 이 경우, @SuppressWarnings("unchecked") 애너테이션을 사용하여 컴파일러 경고를 억제할 수 있습니다. 그러나 이 애너테이션은 가능한 최소 범위에 적용하고, 왜 경고를 억제해야 하는지 주석을 추가하는 것이 좋습니다.

실제 코드 예제

// 비검사 경고가 있는 코드
List myList = new ArrayList();
myList.add("Hello");
String s = (String) myList.get(0);

// 경고를 제거한 코드
List<String> myList = new ArrayList<>();
myList.add("Hello");
String s = myList.get(0);

위의 예제에서 보듯이, 제네릭을 명확히 사용하면 불필요한 캐스팅을 제거하고 코드의 안정성을 높일 수 있습니다.

이렇게 비검사 경고를 제거할 때 주의할 점이 있습니다.

@SuppressWarnings 애너테이션은 항상 가능한 한 좁은 범위에 적용해야합니다.

그 이유는, 너무 넓은 범위에서 이 애너테이션을 사용하면 그 부분에서 발생할 수 있는 다른 중요한 경고 메시지들까지도 숨겨버릴 수 있기 때문입니다. 이렇게 되면 코드의 잠재적인 문제를 감지하고 수정하는 데 어려움이 발생할 수 있습니다.

따라서 @SuppressWarnings 애너테이션은 정말 필요한 최소한의 코드 블록에만 적용해야 합니다. 예를 들어, 특정 메서드나 특정 로컬 변수에만 적용할 수 있습니다.

예제

다음은 @SuppressWarnings 애너테이션을 메서드 레벨과 로컬 변수 레벨에서 적용하는 방법을 보여주는 예시입니다.

메서드 레벨 예시

import java.util.*;

public class Example {
    // 메서드 레벨에서 경고 억제
    @SuppressWarnings("unchecked")
    public void methodWithWarning() {
        List rawList = new ArrayList();
        rawList.add("string");
        rawList.add(10); // 일부러 다른 타입 추가

        List<String> stringList = rawList; // 비검사 캐스트
        for (String s : stringList) {
            System.out.println(s);
        }
    }
}

위 코드에서 @SuppressWarnings("unchecked") 애너테이션은 methodWithWarning 메서드 전체에 적용되었습니다. 이 방식은 해당 메서드 내에서 발생할 수 있는 모든 'unchecked' 경고를 억제합니다. 그러나 이 경우 메서드 내 다른 잠재적인 문제도 눈에 띄지 않게 됩니다.

로컬 변수 레벨 예시

public void morePreciseMethod() {
    List rawList = new ArrayList();
    rawList.add("string");
    rawList.add(10);

    // 로컬 변수 레벨에서만 경고 억제
    @SuppressWarnings("unchecked")
    List<String> stringList = rawList; // 비검사 캐스트

    for (String s : stringList) {
        System.out.println(s);
    }
}

이 코드에서는 @SuppressWarnings("unchecked")를 로컬 변수 선언에만 적용했습니다. 이 방법은 애너테이션이 적용되는 범위를 더욱 좁혀, 다른 코드 부분에서 발생할 수 있는 중요한 경고를 숨기지 않습니다.

정리

비검사 경고는 중요하니 무시하지 말자. 모든 비검사 경고는 런타임에 ClassCastException을 일으킬 수 있는 잠재적 가능성을 뜻하니 최선을 다해 제거하는 게 좋습니다. 경고를 없앨방법을 찾지 못하겠다면, 그 코드가 타입 안전함을 증명하고 가능한 한 범위를 좁혀 @SuppressWarnings("unchecked") 애너테이션으로 경고를 숨기세요. 그런 다음 경고를 숨기기로 한 근거를 주석으로 남기세요.