1. 가변 인수(varargs) 메서드와 제네릭은 잘 어울리지 않는다.
static void dangerous(List<String>... stringLists) {
List<Integer> integerList = Arrays.asList(42);
Object[] objects = stringLists;
objects[0] = integerList;
String s = stringLists[0].get(0); // ClassCastException
}
컴파일 된 class 파일
static void dangerous(List<String>... stringLists) {
List<Integer> integerList = Arrays.asList(42);
stringLists[0] = integerList;
String s = (String)stringLists[0].get(0); Integer -> String 변환 불가
}
마지막 줄에 컴파일러가 생성한 형변환이 숨어 있어 ClassCastException을 던진다.
그래서 제네릭 varargs 배열 매개변수에 값을 저장하는 것은 안전하지 않다.
2. 메서드가 타입 안전한지 보장하는 방법
- varargs 매개변수를 담는 제네릭 배열에 아무것도 저장하지 않는다.
- 배열의 참조가 밖으로 노출되지 않는다.
varargs 배열에 아무것도 저장하지 않고 타입 안정성을 깨는 예 (1번은 지켰지만 2번을 지키지 못함)
public static void main(String[] args) {
String[] strings = pickTwo("a", "b", "c");
}
static <T> T[] pickTwo(T a, T b, T c) {
switch (ThreadLocalRandom.current().nextInt(3)) {
case 0: return toArray(a, b);
case 1: return toArray(a, c);
case 2: return toArray(b, c);
}
throw new AssertionError();
}
private static <T> T[] toArray(T... args) {
return args;
}
// 컴파일된 class 파일
public static void main(String[] args) {
String[] strings = (String[])pickTwo("a", "b", "c"); // ClassCastExceptipon
}
pickTwo 메소드를 본 컴파일러는 toArray에 넘길 T 인스턴스 2개를 담을 varargs 배열을 만드는데 이 배열 타입은 Object[]이다. T에 어떠한 값이 들어와도 다 담을 수 있기 때문이다.
위 코드는 별다른 경고 없이 컴파일이 되지만 실행하면 ClassCastException을 던진다.
pickTwo 메소드가 반환한 배열이 Object[] 타입이 String[] 타입으로 변환할 수 없기 때문이다.
public static void main(String[] args) {
String[] strings = toArray("a", "b", "c");
}
toArray 메소드를 실행한다면 varargs배열 타입을 String으로 추론 가능해서 런타임에도 코드가 정상적으로 작동한다.
- 디버깅 모드로 실행 (toArray호출, pickTwo호출 비교)
즉 varargs 배열의 참조를 밖으로 노출(toArray에서 리턴)하였기 때문에 이 참조를 사용하는 메소드(pickTwo)는 타입 안정성을 보장 받을 수 없게 된다. (2번 규칙 위반)
예외 사항
- @SafeVarargs로 어노테이트된 메서드에 넘기는 것은 안전하다.
- varargs 배열의 일부만을 사용하는 메소드에 넘기는 것도 안전하다.
'effective java' 카테고리의 다른 글
Item 53. 가변인수는 신중히 사용하라 (0) | 2022.03.06 |
---|---|
Item 52. 다중정의는 신중히 사용하라 (0) | 2022.03.06 |
Item46. 스트림에서는 부작용 없는 함수를 사용하라 (0) | 2022.03.06 |
Item 35. ordinal 메서드 대신 인스턴스 필드를 사용하라 (0) | 2022.03.06 |
댓글