[Java] Arrays.asList 와 List.of 의 차이점에 대하여.
0. 들어가며 🏃🏻♂️
자바에서는 간단하게 List를 초기화하려할때 Arrays.asList, List.of와 같은 메서드의 도움을 받기도 합니다. 두 메서드는 비슷한 역할을 하는 것 같은데 차이점이 무엇인지에 대해 궁금증이 생겨 글을 정리하게 되었습니다.
1. Arrays.asList 메서드
Arrays.asList는 자바 1.2에서 생긴 메서드로 List 객체를 보다 편하게 생성할 수 있도록 도와주는 메서드입니다.
사용법은 간단하므로 예시를 통해 알아보도록 하겠습니다.
// 사용법1
List<Integer> asList = Arrays.asList(1, 2, 3, 4);
System.out.println("asList = " + asList); // asList = [1, 2, 3, 4]
// 사용법2
Integer[] array = {1, 2, 3, 4};
List<Integer> asListByArray = Arrays.asList(array);
System.out.println("asListByArray = " + asListByArray); // asListByArray = [1, 2, 3, 4]
위 코드와 같이 asList 메서드를 사용하면 인자로 받은 값을 가지고 적절한 List를 생성해줍니다.
그러면 좀 더 알아보기 위해 asList의 내부는 어떻게 구현되어 있는지 알아보도록 하겠습니다.
asList의 명세를 보게되면 Collection.toArray 메서드와 쌍으로 array - collection 의 가교 역할을 하는 행위를 하는 메서드임을 알 수 있습니다. 또한 인자로 가변 인자를 받음으로써 array 혹은 여러 값을 받을 수 있도록 정의해놓았죠.
특이한 점은 return 값의 ArrayList가 우리가 알고있는 util 클래스의 ArrayList가 아니라는 점입니다. Arrays 클래스에서 구현해놓은 내부 static 클래스인데 이렇게 해논 이유는 asList 명세에서도 볼 수 있듯 fixed-size list를 만들기 위함으로 보입니다.
위 사진에서 볼 수 있듯 Arrays의 내부 클래스인 ArrayList는 add와 remove를 오버라이딩 하지 않았고, 해당 메서드를 호출하게 되면 UnsupportedOperationException가 발생합니다. 추가로 그 외 나머지 메서드는 특별한 점 없이 구현되어있는 것으로 보아 나머지 행위들은 허용하는 것으로 보입니다.
즉, Arrays.asList 메서드는 사이즈에 대한 변경 연산(원소 추가 및 삭제)를 지원하지 않고 fixed-size list를 만들어내는 것을 알 수 있습니다.
2. List.of 메서드
Arrays.asList 메서드와 달리 List.of 메서드는 자바9에서 생긴 새로운 팩토리 메서드입니다. 사용법은 간단하니 아래 코드를 통해 살펴보도록 하겠습니다.
List<Integer> listOf = List.of(1, 2, 3, 4);
System.out.println("listOf = " + listOf); // listOf = [1, 2, 3, 4]
Integer[] array = {1, 2, 3, 4};
List<Integer> listByArray = List.of(array);
System.out.println("listByArray = " + listByArray); // listByArray = [1, 2, 3, 4]
사용법이 Arrays.asList와 동일하죠.
그렇다면 두 메서드의 차이점이 무엇일까요? 이를 알아보기 위해 List.of 내부를 살펴봅시다.
List.of 메서드가 선언된 부분을 살펴보니 unmodifiable list, 즉 불변 List 객체를 리턴해주고 있음을 알 수 있습니다. 여기서 추가로 불변 객체로 만드는 방법이 궁금해져 List.of 메서드의 리턴 값에서 살펴볼 수 있는 ImmutableCollections 클래스를 살펴보았습니다.
살펴보다보니 핵심은 위 사진의 부분이라고 생각했습니다. 사진을 살펴보면 add, addAll, clear.. 등등의 객체 수정 관련 메서드를 호출시 uoe 에러를 던지고 있는 것을 볼 수 있습니다. 이를 통해서 불변객체를 유지하는 것이죠. 추가로 set 메서드의 경우도 오버라이딩하지 않음으로써 같은 에러를 던질 수 있도록 만들어 놓은 것 같습니다.
즉, List.of 메서드의 경우 List의 원소 삭제, 추가와 더불어 수정까지 불가능하게 만든 불변 List 객체를 만들어주는 메서드임을 알 수 있습니다.
3. 결론 ✅
결론적으로 Arrays.asList 메서드의 경우 삭제 및 추가가 불가능하며, List.of의 경우 삭제 및 추가와 더불어 원소의 수정까지 방지합니다. List.of의 경우 불변 객체를 만들어내는 것이죠.
또한 위에서 이야기한 내용 이외에도 Arrays.asList의 경우 참조를 기반으로 동작하기 때문에 원본 배열이 변경될 경우 asList로 리턴받은 list 역시 변화가 일어납니다. side effect가 우려되는 동작방식이죠.
하지만 List.of의 경우 참조 대신 값을 기반으로 독립적인 객체를 만들기 때문에 side effect 우려가 없습니다.
따라서 변경 가능성이 없는 경우 List.of 메서드를 통해 side effect 없는 불변 객체를 만드는 것이 좋은 선택이라고 생각합니다.
4. 레퍼런스 📚
https://www.baeldung.com/java-arrays-aslist-vs-list-of
https://jaehoney.tistory.com/144