자바에서 보통 List로 변환하기 위해서는 Arrays.asList(array)를 사용합니다.
Java 9 버전 부터는 List.of(array)라는 새로운 팩토리 메소드가 있습니다.
이 둘의 차이점은 무엇일까 ? 어떤걸 사용하면 될까 ?
라는 고민을 시작으로 글을 작성했습니다.
Arrays.asList()
에서 반환된 List는 변경이 가능합니다.
하지만, List.of()
에서 반환된 List는 변경이 불가능합니다.
대표적으로 set()
메서드를 사용해보면 둘의 차이를 알 수 있습니다.
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)
(참고) Arrays.asList()가 반환하는 ArrayList 타입은
java.util.ArrayList
가 가 아니라Arrays 내부 클래스
입니다. add()와 remove() 메서드는 구현되어 있지 않아서, 배열의 크기 변동과 관련된 행동은 할 수 없습니다.
반면, List.of()
는 ListN
이라는 타입의 객체를 반환하는데, 이는 불변 객체(Immutable object)입니다. 따라서 수정할 수 없습니다.
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체크를 하고, 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)
는 참조를 넘겨주기 때문에 original
배열의 값이 변경되면 새로 할당한 변수 newPointer
에도 영향이 갑니다.
Integer[] original = {1,2};
List<Integer> newPointer = Arrays.asList(original);
original[0] = 100;
System.out.println(newPointer); // [100, 2]
반대로 newPointer
를 set()
으로 원소를 변경하면 original
에도 영향이 가는건 당연하겠죠.
List.of(original)
의 결과는 값을 기반으로 독립적인 객체를 만들기 때문에 참조가 일어나지 않습니다.
Integer[] original = {1,2};
List<Integer> list = List.of(original);
original[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을 생성해서 요소의 값을 옮겨야 합니다.
소중한 정보 잘 봤습니다!