Language/Java

Java - Arrays.asList vs List.of 차이 (완벽 정리)!

JaeHoney 2022. 3. 27. 12:07

Arrays.asList() / List.of

자바에서 Array를 List으로 변환하기 위해서는 Arrays.asList(array)를 사용합니다.

 

Java 9 버전 부터는  List.of(array)라는 새로운 팩토리 메소드를 도입했습니다.

 

차이점은 무엇일까요 ? 뭐가 좋은 걸까?

 

변경 가능 여부 (Mutable / Immutable)

Arrays.asList()로 반환된 list는 변경이 가능합니다. 하지만, List.of()에서 반환된 메서드는 변경이 불가능합니다.

List<Integer> list = Arrays.asList(1, 2, null);
list.set(1, 10); // OK

List<Integer> list = List.of(1, 2, 3);
list.set(1, 10); // Fails with UnsupportedOperationException

이유는 Arrays.asList()는 ArrayList를 반환하고, set등이 구현되었습니다. (Arrays 내부 클래스 ArrayList)

 

반면, List.of()는 ListN이라는 타입의 객체를 반환하는데, 이는 불변 객체(Immutable object)입니다. 따라서 수정할 수 없습니다.

 

(참고) Arrays.asList()가 반환하는 ArrayList 타입은 java.util.ArrayList가 가 아니라 Arrays 내부 클래스입니다. add와 remove는 구현되어 있지 않아서, 크기는 변경할 수 없습니다.

 

Null 허용 여부

Array.asList()는 null을 허용합니다. List.of()는 반환 객체가 생성될 때, 내부적으로 파라미터들에 대한 null체크를 하고 null을 허용하지 않습니다.

List<Integer> list = Arrays.asList(1, 2, null); // OK
List<Integer> list = List.of(1, 2, null); // Fails with NullPointerException

List.of()로 반환된 객체의 contains의 경우 파라미터로 null이 들어오면 NPE(Null pointer exception)이 발생합니다.

List<Integer> list = Arrays.asList(1, 2, 3);
list.contains(null); // Returns false

List<Integer> list = List.of(1, 2, 3);
list.contains(null); // Fails with NullPointerException

 

참조 / 비참조

앞서 살펴본, Arrays.asList(array)의 객체로 add와 remove를 구현할 수 없는 이유는 참조로 동작하기 때문입니다. 배열은 크기를 늘리거나 줄일 수 없죠.

 

Arrays.asList(array)는 참조를 사용하기 때문에 배열의 값이 변경되면 list에도 영향이 갑니다.

Integer[] array = {1,2};
List<Integer> list = Arrays.asList(array);
array[0] = 100;
System.out.println(list); // [100, 2]

List.of(array)의 결과는 값을 기반으로 독립적인 객체를 만들기 때문에 참조가 일어나지 않습니다.

Integer[] array = {1,2};
List<Integer> list = List.of(array);
array[0] = 100;
System.out.println(list); // [1, 2]

 

메모리 사용

Arrays.asList()는 List.of()보다 힙에 더 많은 개체를 생성하기 때문에 더 많은 오버헤드 공간을 차지합니다. 따라서, 단지 값 요소가 필요한 경우라면 List.of()가 적합합니다.

 

변환

예를 들어, Array를 ArrayList 또는 HashSet 등으로 변환하기 위해서는, 참조나 변경 가능 여부는 상관없고 요소만 알면 됩니다. 이 때는 List.of()가 적합합니다.

List<String> list = new ArrayList<>(List.of(array));
Set<String> set = new HashSet<>(List.of(array));

 

 


요약

위에서 언급한 내용을 종합해서 정리한 내용은 다음과 같습니다.

  • Arrays.asList()는 크고 동적인 데이터에 사용하고, List.of()는 작고 변경되지 않는 데이터의 경우 사용합니다.
  • List.of()는 필드 기반 구현이 있고, 내부적으로 힙 공간을 덜 사용하기에 요소 자체가 필요하다면 List.of()가 적절합니다.
  • Arrays.asList()는 변경이 가능하고 thread safety 하지 않고, List.of()는 불변하고 thread safety합니다. 
  • Arrays.asList()는 null 요소를 허용하고 List.of()는 null 요소를 허용하지 않습니다.
  • Arrays.asList(), List.of() 모두 크기는 변경할 수 없다. 크기를 바꾸려면 Collections을 생성해서 요소의 값을 옮겨야 합니다.

 

Reference: What is difference between List.of vs Arrays.asList

 

감사합니다.