이펙티브 자바 아이템32

한주영·2024년 1월 25일
0

이펙티브자바

목록 보기
24/33

제네릭과 가변인수를 쓸 때는 신중하라

가변인수 메서드

가변인수:메서드에 넘기는 인수의 개수를 클라이언트가 조절할수있게 해준다.
가변인수 메서드를 호출하면 가변인수를 담기위한 배열이 생성됨
->varags 매개변수에 제네릭이나 변수화 타입이포함될시 컴파일 경고 발생

warning: [unchecked] Possible heap polluation from
       parameterized vararg type List<String>

1.매개변수화 타입의 변수가 타입이 다른객체를 참조하면 힙 오염이 발생

static void dangerous(List<String>...stringLists)
    List<Integer> intList=List.of(42);
    
    Object[] objects=stringLists;
    objects[0]= intList;  //힙 오염 발생
    String s= stringLists[00.get(0) //ClassCastException

=> 타입 안정성이깨지므로 제네릭 varags메서드열 매개변수에 값을 저장하는것은 안전하지않다.

  1. @SafeVarags 애너테이션이 추가되어 제네릭 가변인수 메서드 작성자가 클라이언트 측에서 발생하는 경고를 숨길수있게됨.
    =>메서드 작성자가 그 메서드 타입 안전함을 보장하는 장치

3.가변인수 메서드를 호출할때 varargs매개변수를 담는 제네릭 배열이 만들어진다는 사실을 기억해야함!

=> 이때 varargs매개변수 배열에 아무것도 저장하지않고도 타입안정성을 깰수있으니 주의해야함

static<T> T[] toArray(T... args){
     return args;
}

위코드에서는 자신의 제네릭 매개변수가 배열의 노출을 참조하므로 안전하지 않은 코드이다.

4.제네릭 varargs 매개변수를 안전하게 사용하는메서드
-> 제네릭이나 매개변수화 타입의 varargs매개변수를 받는 모든 메서드에 @SafeVarargs를 달라
-> 사용자를 헷갈리는 컴파일러 경고를 없앨수있다

@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;
}

->varargs매개변수를 List매개변수로 바꿀수도있다
->List로 대체한 예

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

이 방식의 장점
1) 컴파일러가 메서드의 타입 안정성을 검증할수있다
2) @SafeVarargs 애너테이션 직접 달지않아도 된다
3) List.of를 활용하면 메서드에 임의개수 인수를 넘길수있다.

핵심정리

1)가변인수와 제네릭은 궁합이 좋지않다
-> 가변인수 기능은 배열을 노출하여 추상화가 완벽하지못하고, 배열과 제네릭의
타입 규칙이 서로 다르기 때문
2) 제네릭 varargs 매개변수는 타입이 안전하진 않지만 하용된다
-> 해당 변수를 사용하고자하면 먼저 그 메서드 타입이 안전한지 확인
@SafeVarargs 애너테이션을 달아서 사용불편을 줄이자

profile
백엔드개발자가 되고싶은 코린이:)

0개의 댓글