이펙티브 자바 아이템28

한주영·2023년 12월 21일
0

이펙티브자바

목록 보기
20/33

배열보다는 리스트를 사용하라

첫번째 배열은 공변:함께변한다

제네릭은 불공변:함께 변하지않는다

런타임실패

Object [] objectArray= new Long[1];
ObjectArray[0]="타입이 달라 넣을수없다";

컴파일 실패

List<Object> objectList = new ArrayList<>(); // 호환되지 않는 타입이다.
objectList.add("타입이 달라 넣을 수 없다.");

두번째 배열은 실체화된다

배열은 자신이 담기로한 원소의 타입을 인지하고 확인
Long타입 배열에 String타입 데이터를 입력하면 ArrayStoreException이 발생

반면, 리스트는 타입 정보가 런타임에는 소거된다.

이런 이유로 배열은 제네릭 타입(new List[]), 매개변수화 타입(new List[]), 타입 매개변수(new E[]) 로 사용할 수 없다. 이런 식으로 코드를 작성하려하면 제네릭 배열 생성 오류를 일으킨다.

[제네릭 배열 생성을 허용하지 않는 이유 - 컴파일되지 않는다.]

제네릭 배열을 만들지 못하게하는 이유는 컴파일러가 자동 생성한 형변환 코드에서 런타임에 ClassCastException이 발생할 수 있기 때문에 타입 안전하지 않기 때문

실체화 불가 타입

E, List, List 같은 타입을 실체화 불가 타입이라고 한다.

실체화 되지 않아서 런타임에는 컴파일보다 타입정보를 작게 가지는 타입

실체화될 수 있는 타입은 List, Map 같은 비한정적 와일드카드 타입

@SafeVarargs
@SafeVarargs는 메서드 작성자가 해당 메서드가 타입 안전하다는 것을 보장하는 장치이다.

배열대신 컬렉션을 사용하자.

배열로 형변환할때 제네릭 배열 생성오류나 비검사 형변환 경고가 뜨는경우에
배열 E[]대신 List를 사용하면 해결된다.

Chooser - 제네릭 적용 필요

public class Chooser {
    private final Object[] choiceArray;

    public Chooser(final Object[] choiceArray) {
        this.choiceArray = choiceArray;
    }

    public Object choose(){
        Random random = ThreadLocalRandom.current();
        return choiceArray[random.nextInt(choiceArray.length)];
    }
}

위 클래스를 사용하려면 choose 메서드를 호출할 때마다 반환된 Object를 원하는 타입으로 형변환해야 한다. 만약 타입이 다른 원소가 들어있으면 런타임시에 형변환 오류가 발생한다.

리스트 기반 Chooser - 타입 안정성 확보

public class ListChooser {
    private final List<T> choiceList;

    public ListChooser(final Collection<T> choices) {
        this.choiceList = new ArrayList<>(choices);
    }
    
    public T choose(){
        Random random = ThreadLocalRandom.current();
        return choiceList[random.nextInt(choiceList.size())];
    }
}

리스트를 사용함으로써 런타임에 ClassCastException을 만날일이 없어짐

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

0개의 댓글