27. 비검사 경고를 제거하라

가능한 모든 비검사 경고는 제거하라!

📌 1. 발표 전 알아야 할 개념

✅ 로타입(RawType)

  • 제네릭 타입에서 타입 매개변수를 전혀 사용하지 않을 때

List list = new ArrayList();
  • 타입 안정성을 보장하기 어려움


📕 2. 비검사 경고 완전 정복

2-1. 비검사 경고(Unchecked Warning)

  • 자바의 제네릭 시스템이 컴파일 시점에서 타입 안전성을 완전히 검증할 수 없을 때 컴파일러가 발생시키는 경고

2-2. 비검사 경고의 종류

  • 비검사 형변환 경고 (Unchecked Cast Warning)

    • 로 타입입을 제네릭 타입으로 형변환할 때, 컴파일러가 검증할 수 없는 형변환일 경우

    List car = new ArrayList();
    List<Car> myCar = (List<Car>) car;
(우리는 일반적으로 제네릭을 사용하고 있다!)
  • 비검사 메서드 호출 경고 (Unchecked Method Invocation Warning)

    • 제네릭 타입이 있는 메서드에서 토 타입을 사용할 때 발생

public class Car {
    String model;
    Car(String model) {
        this.model = model;
    }
}

public class UncheckedMethodWarning {
    public static void main(String[] args) {
        List cars = new ArrayList();
        addCar(cars, new Car("Tesla"));
    } // cars는 로 타입입
    public static void addCar(List<Car> carList, Car car) {
        carList.add(car);
    } // 제네릭 타입 메서드
} // 제네릭 타입이 있는 메서드에서 로 타입 사용 시
Image
  • 비검사 메개변수화 가변인수 타입 경고 (Unchecked Generic Array Creation Warning)

    • 제네릭 타입이 있는 배열을 가변인수(varargs)로 사용할 때 발생

    • 주로 배열과 제네릭을 함께 사용할 때 발생(배열은 타입을 유지하는데 제네릭은 컴파일 후 타입이 소거됨)

    • @SafeVarargs 어노테이션을 메서드 위에 붙여 경고를 억제함

class UncheckedVarargs {
    public static <T> void rentCars(List<T>... carList) {
        for(List<T> list : carList) {
            System.out.println("Rent: "+list);
        }
    }

    public static void main(String[] args) {
        List<Car> ElectricCars = Arrays.asList(new Car("Tesla"), new Car("Ionic"));
        rentCars(ElectricCars);
    }
}
Image
  • 비검사 변환 경고

    • 제네릭이 없는 로로 타입을 제네릭 타입 변수에 할당 시 발생

List cars = new ArrayList(); // 로로 타입
List<Car> carList = cars;

🐍 3. 비검사 경고를 제거하자!

  • 비검사 경고를 그냥 둔다면?

    • ClassCastException 런타임 에러 발생 가능

    • 치명적인 경고가 발생해도 확인하기 힘들다

  • 비검사 경고 제거릍 통해 타입 안정성 보장

  • 가독성 향상 및 유지 보수 용이

3-1. 제네릭 타입을 사용하기

  • 로타입을 사용하지 않고 구체적인 타입 지정하기

  • 다이아몬드 연산자(<>) 사용하기

  • 제네릭을 사용하여 타입 안정성을 확보한다

List strings = new ArrayList(); // ❌
List<String> strings = new ArrayList<>(); // 🆗

3-2. @SuppressWarnings("unchecked")를 최소한으로 사용하기 💥

  • 비검사 경고를 제거할 수는 없지만, 타입 안정성이 확실하다면! @SuppressWarnings("unchecked") 애너테이션을 달자

  • 단, @SuppressWarnings 애너테이션은 항상 가능한 좁은 범위(변수, 메서드, 클래스 순)에 적용해야 한다.

  • 안전한 이유를 항상 주석으로 남겨야 한다. (@SuppressWarnings를 사용해도 되는 이유)

public class SuppresssWarningTest {
    @SuppressWarnings("unchecked")
    // carList 리스트에는 Car 객체만 추가 되어 타입이 모두 같다
    // 타입 안정성이 보장된다
    private static List<Car> cars = (List<Car>) new ArrayList();

    public static void main(String[] args) {
        cars.add(new Car("Tesla"));
        cars.add(new Car("Ionic"));

        for (Car car : cars) {
            System.out.println(car.model);
        }
    }
}

🤖 최종 결론

모든 비검사 경고는 잠재적인 ClassCastException을 뜻한다 가능한 모든 비검사 경고를 제거하라. 제거할 수 없는 경고는 가능한 좁은 범위에 @SuppressWarnings("unchecked")로 숨기고 이유를 주석으로 남겨라


❗어려웠던 점

  • 처음에 로 타입에 대한 이해가 명확하지 않아서 어려웠는데, 우리가 코드를 작성할 때 자연스럽게 제네릭 타입을 잘 활용하고 있었다!


😶‍🌫️ 느낀점

  • 경고는 잘 확인하지 않고 넘어가는 경우가 많았는데, 비검사 경고처럼 향후 런타임에 문제가 발생할 수도 있는 경고의 경우 잘 확인하고 넘어가야겠다.

Last updated