이펙티브 자바 #item28 배열보다는 리스트를 사용해라

임현규·2023년 2월 2일
0

이펙티브 자바

목록 보기
28/47
post-thumbnail
post-custom-banner

공변 (Convarint)

배열은 공변, 제네릭은 불공변이라 한다. 공변이란 무엇인가?

공변은 Sub가 Super의 하위 타입이라면 해당 타입 즉 배열에서도 Sub[]가 Super[]의 하위 타입이 된다. 즉, 이전 특성이 타입이 변해도 공변이라면 동일하게 특징을 가져온다는 특성이 있다.

제네릭은 List<type1> 와 List<type2> 모두 전혀 다른 타입이다. 상위, 하위 타입과도 전혀 관계가 없다.

제네릭이 배열에 비해 타입 안정성이 좋다.

제네릭의 특성은 컴파일시에 비교를 하고 매개변수가 소멸한다. 그 이후 런타임에서는 따로 검사를 하지 않는다. 뭐든지 오류는 런타임보다는 컴파일 시점에서 파악하는 것이 오류를 해결하는데 훨씬 도움이 된다. 그러나 배열의 공변 특성 때문에 컴파일에서 타입이 잘못되도 잡을 수 없다.

// 런타임 실패 코드
Object[] objectArray = new Long[1];
objectArray[0] = "hello"; // throw ArrayStoreException

배열로 선언한 경우 컴파일러는 이를 잡을 수 없다. 타입은 Object로 정의 했으나 실제 생성되는 배열의 타입은 Long이다. Long[]은 Object[]의 서브타입이기 때문에 컴파일 단계에서는 문제가 없다. 그리고 "hello"라는 문자열타입이 입력되고 나서야 런타임에 저장할수 없다는 예외가 발생한다.

// 컴파일 실패 코드
List<Object> ol = new ArrayList<Long>(); // 타입이 다르므로 컴파일 실패
ol.add("hello");

제네릭은 비공변이다. Long은 Object의 하위 타입이지만 List<Long>은 List<Object>의 하위타입이 아니다. 그렇기에 타입이 다르고 컴파일에서 오류가 발생한다.

하위 타입을 활용하려면 배열을 써야되지 않나?

제네릭에서는 이를 해결하기 위해 비한정적 와일드카드 타입을 지원한다.
만약 Object의 하위 타입을 담고 싶다면 다음과 같이 정의하면 된다.

// 비한정적 와일드카드 타입
List<? extends Object> ol = new ArrayList<Long>();

비검사 경고를 확실하게 제거할 수 있다.

Object[]를 쓰면 형변환을 해야하고 타입에 대한 여러 경고가 뜰 수 있다. 이를 제네릭을 활용하면 효과적으로 없앨 수 있다.

// 제네릭을 적용해야한다.
public class Chooser {
	private final Object[] choiceArray;
    
    public Chooser(Collection choices) {
    	choiceArray = choices.toArray();
    }
}
// 컴파일 에러
public class Chooser {
	private final T[] choiceArray;
    
    public Chooser(Collection<T> choices) {
    	choiceArray = (T[])choices.toArray();
    }
    

그러나 이 코드는 경고를 발생한다. 바로 (T[])로 형변환 하는 부분인데 해당 형변환이 런타임에도 안전한지 보장할 수 없기 때문이다. 주석을 남기고 애너테이션을 적용해서 경고를 숨기는 방법도 있지만 사람의 개인적인 판단은 100% 안전하다고 보장할 수 없다. 이럴 때 배열대신 리스트를 사용하면 쉽게 해결한다.

public class Chooser {
	private final List<T> choices;
    
    public Chooser(Collection<T> choices) {
    	choices = new ArrayList<>(choices);
    }
}

List는 분명 배열보다 성능이 좋지 않을 수 있다. 기본적으로 클래스이고 배열에 비해 약간 무겁기 때문이다. 그러나 런타임에 ClassCastException에 대해서는 안전함을 100% 보장한다. 성능을 조금 희생하더라도 리스트를 사용하는 것은 확실히 가치가 있다.

profile
엘 프사이 콩그루
post-custom-banner

0개의 댓글