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

청포도봉봉이·2024년 2월 11일
1

java

목록 보기
11/20
post-thumbnail

Effective Java의 Item 28 "배열보다는 리스트를 사용하라"의 내용입니다.

Item 28 배열보다는 리스트를 사용하라의 핵심 개념은 배열과 제네릭은 근본적으로 다른 타입 규칙을 가지고 있기 때문에 둘을 섞어 사용하면 오류가 발생할 수 있다는 것입니다.

배열

배열(Array)은 같은 타입의 여러 데이터를 하나의 변수에 저장할 수 있는 구조를 말합니다. 예를 들어, int형 배열은 여러 개의 int 값을 한꺼번에 저장할 수 있습니다.

제네릭

제네릭(Generic)은 클래스나 메서드에서 사용할 내부 데이터 타입을 컴파일 시점에 미리 지정하는 방법을 말합니다. 예를 들어, List<String>은 String 타입의 데이터만 담을 수 있는 리스트를 만듭니다.

공변(Covariant)

공변(Covariant)은 한 타입이 다른 타입의 하위 타입(subtype)으로 간주 될 수 있을 때, 이 두 타입을 '공변'이라고 합니다. 예를 들어, 모든 문자열(String)은 객체(Object)이므로, 문자열은 객체의 하위 타입이라고 할 수 있습니다.

공변이라는 단어에서부터 이해가 잘 안됩니다. 그래서 예시를 보면서 이해해보도록 합시다.

예를 들어, 상위 클래스(Super)가 있고 이를 상속하는 하위 클래스(Sub)가 있습니다.

Super sub = new Sub();

배열에서의 공변은 아래처럼 배열에서도 함께 변해서 적용된다는 뜻입니다.

Super[] sub = new Sub[]{};

Ex)

Object[] objectArray = new String[1];
objectArray[0] = "hi"; // 이것은 잘 동작합니다.

String은 Object의 서브타입이므로 String배열은 Object배열로도 변할 수 있습니다.

Ex)

Object[] objects = new Long[1];
objects[0] = "나는 String이라서 들어가면 안돼요";

Long 클래스는 Object 클래스를 상속받습니다. 위 코드는 컴파일 시점에선 에러가 나지 않지만 코드 실행 후 런타임 시점에서 에러가 발생합니다.

불공변

불공변이라는 용어는 타입 시스템에서 사용되는 개념으로, 한 타입이 다른 타입의 서브타입(subtype)이 아니라는 것을 의미합니다.

List<Super> subs = new ArrayList<Sub>(); // 같은 타입이 아니므로 컴파일 에러!

위 코드처럼 Sub가 Super를 상속하더라도 같은 타입이 아니면 컴파일 에러가 뜹니다.

Ex)

List<Object> list = new ArrayList<Long>();
list.add("test");

위에 말한 것처럼 Long이 Object를 상속하더라도 같은 타입이 아니기때문에 컴파일 에러가 뜨게 됩니다.

따라서, 리스트를 사용하면 컴파일 시점에 오류를 잡아낼 수 있고, 이는 런타임에 발생할 수 있는 오류를 사전에 예방할 수 있습니다.

배열과 제네릭을 같이 쓴다면?

그러나, 배열과 제네릭을 섞어 사용하면 오류가 발생할 수 있습니다. 예를 들어, 제네릭 타입의 배열을 생성하려고 하면 컴파일 오류가 발생합니다.

List<String>[] list = new List<String>[1];

위 코드는 컴파일 오류가 발생합니다.

List<String>[] stringLists = new List<String>[1];  // 컴파일 에러
List<Integer> intList = Arrays.asList(42);
Object[] objects = stringLists;  // 배열은 공변이므로 이 작업은 허용됩니다.

위의 코드에서 stringLists는 List<String>의 배열이므로, 이 배열의 각 원소는 문자열 리스트가 되어야 합니다.
그러나 배열의 공변성과 제네릭의 타입 소거 때문에, 우리는 List<Integer>를 stringLists[0]에 할당할 수 있게 됩니다.

이는 배열이 런타임에 자신의 원소를 확인하는 반면, 제네릭은 타입 정보가 런타임에 지워지기 때문에(타입 소거)배열과 제네릭이 함께 사용될 때 타입 안정성을 보장할 수 없기 때문입니다.

배열보다 리스트를 사용하면 좋은 이유

  1. 타입 안전성: 리스트는 컴파일 시점에 타입 검사를 수행하기 때문에, 실행 중에 발생할 수 있는 타입 오류를 사전에 방지합니다.
  2. 유연성: 리스트는 크기 변경이 자유롭고, 풍부한 API를 제공합니다.
    기능: 리스트는 다양한 기능(검색, 정렬 등)을 제공합니다.

출처

profile
서버 백엔드 개발자

0개의 댓글