본문 바로가기

1_스터디

[EffectiveJava]ITEM 32. 제네릭과 가변인수를 함께 쓸 때는 신중하라

반응형

가변인수 메서드

가변인수(varargs) 메서드와 제네릭은 함께 사용이 어렵다.
가변인수는 메서드에 넘기는 인수의 개수를 클라이언트가 조절할 수 있게 해준다.
가변인수 메서드를 호출하면 가변인수를 담기 위한 배열이 자동으로 하나 만들어진다.
그런데 내부로 감춰야 했을 이 배열을 클라이언트에 노출시키는 문제가 생겼다. 그 결과 varargs 매개변수에 제네릭이나 매개변수화 타입이 포함되면 알기 어려운 컴파일 경고가 발생한다.

static void dangerous(List<String>... stringLists) {
    List<Integer> intList = List.of(2);
    Object[] objects = stringLists;
    objects[0] = intList; // 힙 오염 
    /* stringList 는 Integer 타입으로 변경됨 */
    String s = stringLists[0].get(0); // ClassCastException 발생
}

 

@SafeVaragrs

메서드 작성자가 이 메서드가 '타입안전함'을 보장하는 장치.
소비자(사용자)가 Warning을 컨트롤 하지 않아도 된다.

메서드가 '타입안전함'을 확신하는 방법
- 매개변수 배열이 순수하게 '인수들을 전달하는 일'만 한다면 그 메서드는 안전하다.

 

제네릭 varargs 매개변수 안전하게 사용하는 방법

@SafeVarargs
static <T> List<T> flatten(List<? extends T>... lists) {
    List<T> result = new ArrayList<>();
    for (List<? extends T> list : lists) {
        result.addAll(list);
    }
    return result;
}

flatten 메서드는 임의 개수 리스트를 인수도 받아, 받은 순서대로 그 안의 모든 원소를 하나의 리스트로 옮겨 담아 반환한다. 이 메서드는 제네릭 varargs 매개변수를 안전하게 사용하는 예다. 따라서 @SafeVarargs 어노테이션도 달아야한다.

@SafeVarargs 어노테이션을 사용할때는 제네릭이나 매개변수화 타입의 varargs 매개변수를 받는 모든 메서드에 @SafeVarargs를 달아라. 그래야 사용자를 헷갈리게 하는 컴파일러 경고를 없앨 수 있다. 이 말은 안전하지않은 varargs 메서드는 절대 작성해서는 안된다는 뜻이기도 하다.

1. varargs 매개변수 배열에 아무것도 저장하지 않는다.
2. 그 배열(혹은 복제본)을 신뢰할 수 없는 코드에 노출하지 않는다.

 

반응형