본문 바로가기

STUDY/이펙티브자바

5-3) 배열보다는 리스트를 사용하라

배열과 제네릭의 차이

 

// 컴파일 에러가 발생하지 않는다.
Object[] objectArray = new String[1];

// 컴파일 에러가 발생한다.
List<Object> objectList = new ArrayList<String>()

배열에서는 Sub가 Super의 하위 타입이라면 Sub[]는 Super[]의 하위타입이 된다. 리스트에서는 List<Sub>가 List<Super>의 하위타입이 아니다. 따라서 위의 코드를 보면 배열에서는 가능한 코드가 리스트에서는 컴파일 에러가 발생한다. 배열이 더 유연한 코드를 제공하는거 같지만 실제로는 위험한 코드를 허용해주는 것이다. 배열의 저러한 특성때문에 아래의 코드같이 런타임에 문제가 생길 수 있다.

 

// 런타임에서 발생
Object[] objectArray = new String[1];
objectArray[0] = 3;

 

 


제네릭 적용하기

 

public class Chooser {
    private final Object[] choiceArray;

    public Chooser(Collection choices) {
        choiceArray = choices.toArray()
    }

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

Collection 타입의 인스턴스를 받아서 랜덤한 객체를 하나씩 뽑아내는 Chooser 클래스가 있다. 하지만 해당 클래스는 choose 메소드를 호출할 때마다 반환된 Object를 원하는 타입으로 변환해야 한다. 이 클래스를 제네릭을 사용하더 개선해보고자 한다.

 

public class Chooser<T> {
    private final T[] choiceArray;

    public Chooser(Collection<T> choices) {
        choiceArray = (T[]) choices.toArray();
    }

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

제네릭을 사용하여 Chooser 클래스를 생성할때 타입 파라미터를 전달하여 choose 때마다 형변환을 할 필요가 없도록 하였다. 하지만 choiceArray = (T[]) choices.toArray(); 부분에서 형변환 경고가 발생한다. 물론 이를 무시할 수 있겠지만, 추후 런타임에서 문제가 생길 수 있기때문에 배열 대신 List를 사용하여 형변환 경고를 없애보고자 한다.

 

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

    public Chooser(Collection<T> choices) {
        choiceList = new ArrayList<>(choices);
    }

    public T choose() {
        Random rnd = ThreadLocalRandom.current();
        return choiceList.get(rnd.nextInt(choiceList.size()));
    }
}

 

728x90