List.of와 Arrays.asList의 차이점은 무엇입니까?


117

Java 9는 목록에 대한 새로운 팩토리 메소드를 도입했습니다 List.of.

List<String> strings = List.of("first", "second");

이전 옵션과 새 옵션의 차이점은 무엇입니까? 즉, 이것의 차이점은 무엇입니까?

Arrays.asList(1, 2, 3);

이:

List.of(1, 2, 3);

1
Stuart "Beaker"Marks 의이 강연 도 참조하십시오 .
user1803551

20
@ user1803551 귀하의 좌절감을 이해하지만이 추론은 정말 원치 않는 선례를 설정할 수 있습니다. 여기에있는 많은 질문에는 '명확하게 명시된'답변이 있습니다 (이를 정의하는 방법에 따라 다름). 나는 메타이 토론을 가지고 당신을 촉구 싶지만 이미 존재해야 확신 이러한 토론 해요 (나는 :-) 누군가를 찾아 연결할 수 있습니다 바라고 있어요
디미트리 Fasarakis 힐리

4
@ user1803551 Javadocs는 이러한 두 메서드의 구현 세부 정보 (예 : 공간 소비 또는 성능) 간의 차이점을 언급하지 않습니다. 나는 사람들이 이러한 세부 사항도 알고 싶어한다고 생각합니다.
ZhekaKozlov

5
@ZhekaKozlov 수락되고 슈퍼 찬성 응답도 마찬가지입니다. 허용되는 표준에 대해 무엇을 알려 줍니까? 문서 (직렬화, ID, 순서) 보다 정보 가 적습니다 . 해당 정보를 추가하려면 OpenJDK에 요청을 제출하십시오.
user1803551 2017-10-06

3
이 질문은 meta 에서 논의되고 있습니다.
Dimitris Fasarakis Hilliard

답변:


173

Arrays.asList에서 반환 된 목록 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다음을 List.of수행하지 않는 동안 null 요소를 허용합니다 .

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

contains null과 다르게 동작합니다.

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전달 된 배열의보기를 반환하므로 배열의 변경 사항도 목록에 반영됩니다. 들어 List.of이 사실이 아니다 :

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

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

22
목록이 구성되는 방식에 따라 다르게 작동하는 것은 저에게 객체 지향적이지 않습니다. 아마도 List.of가 ImmutableList 유형을 반환했다면 이것은 의미가있을 것입니다. 이것은 여기에서 매우 새는 추상화입니다.
Sandy Chapman

5
저는 Java 개발자가 아니므로 우연히 관찰하십시오. 동작이 다를 수있는 좋은 이유가있을 수 있지만 예제와 같이 List <Integer>를 반환하는 메서드가있는 경우 확인하면 런타임 예외가 발생하는지 알기에 인터페이스가 충분하지 않습니다. null의 경우. 마찬가지로 메서드 구현의 변경 사항은 검사가 다른 곳에서 발생하는 경우 내 메서드의 호출 사이트에서 멀리 떨어진 코드에 영향을 미칠 수 있습니다. @Nicolai
Sandy Chapman

8
@SandyChapman 이것은 일부 (또는 대부분?)에게 예상치 못한 동작 일 수 있지만 문서화 된 동작입니다. 로부터 List.contains(Object o)의 javadoc의 "예외 [...] - 지정된 요소가 null이며,이리스트가 null 요소 (선택을) 허용하지 않을 경우". 또는 거의 읽지 않은 인터페이스의 긴 소개에서 "일부 컬렉션 구현에는 포함 할 수있는 요소에 대한 제한이 있습니다."
Aaron

11
@Aaron 잘 적어도 그건 잘 문서화 새는 추상화 :
샌디 채프먼

6
@Sandy 채프먼 : List.of 않는 일부 반환 ImmutableList유형을, 실제 이름은 단지 비공개 구현 세부입니다. 공개되고 누군가가 List다시 캐스팅했다면 차이점은 무엇입니까? 또는 시도 할 때 예외를 발생시키는 Arrays.asList비공개 List구현 을 반환하는 , 또는 수정이 전혀 허용되지 않는에서 반환 된 목록 의 차이점 은 무엇입니까? 인터페이스에 지정된 계약에 관한 것 입니다. 선택적 메소드가있는 Collections 인터페이스는 Java 1.2 이후 항상 불순한 OOP였습니다…addremoveCollections.unmodifiableListList
Holger

31

사이의 차이 Arrays.asListList.of

JavaDocs 및 Stuart Marks (또는 이전 버전) 의이 강연 을 참조하십시오 .

코드 예제로 다음을 사용하겠습니다.

List<Integer> listOf = List.of(...);
List<Integer> asList = Arrays.asList(...);
List<Integer> unmodif = Collections.unmodifiableList(asList);

구조적 불변성 (또는 : 수정 불가능)

구조적으로 변경 하려는 시도 List.ofUnsupportedOperationException. 여기에는 추가 , 설정제거 와 같은 작업이 포함됩니다 . 그러나 목록에있는 개체의 내용을 변경할 수 있으므로 (개체가 변경 불가능하지 않은 경우) 목록이 "완전히 변경 불가능"하지 않습니다.

로 생성 된 수정 불가능한 목록의 운명과 동일 Collections.unmodifiableList합니다. 이 목록 만 원래 목록 보기 이므로 원래 목록을 변경하면 변경 될 수 있습니다.

Arrays.asList완전히 변경할 수 없으며에 대한 제한이 없습니다 set.

listOf.set(1, "a");  // UnsupportedOperationException
unmodif.set(1, "a"); // UnsupportedOperationException
asList.set(1, "a");  // modified unmodif! unmodif is not truly unmodifiable

마찬가지로 백업 배열을 변경하면 (보유하고있는 경우) 목록이 변경됩니다.

구조적 불변성은이 답변의 범위를 벗어난 방어 코딩, 동시성 및 보안과 관련된 많은 부작용을 동반합니다.

무적의 적대감

List.ofJava 1.5 이후의 모든 컬렉션 null은 요소로 허용되지 않습니다 . null요소 또는 조회 로 전달하려고 시도 하면 NullPointerException.

이후 Arrays.asList1.2에서 컬렉션 (컬렉션 프레임 워크), 그것이 허용 null들.

listOf.contains(null);  // NullPointerException
unmodif.contains(null); // allowed
asList.contains(null);  // allowed

직렬화 된 형식

때문에 List.of자바 (9) 도입 및이 방법에 의해 생성 된리스트는 자신의 (바이너리) 직렬화 된 형식을 가지고있다, 그들은 이전 JDK 버전 (NO 역 직렬화 할 수없는 바이너리 호환성 ). 그러나 예를 들어 JSON을 사용하여 역 직렬화 할 수 있습니다.

정체

Arrays.asList내부적으로를 호출 new ArrayList하여 참조 부등식을 보장합니다.

List.of내부 구현에 따라 다릅니다. 반환 된 인스턴스는 참조 동등성을 가질 수 있지만 이것이 보장되지 않으므로 신뢰할 수 없습니다.

asList1 == asList2; // false
listOf1 == listOf2; // true or false

목록 List.equals이 생성 된 방법이나 지원하는 작업에 관계없이 동일한 순서로 동일한 요소를 포함하는 경우 목록은 동일합니다 (를 통해 ).

asList.equals(listOf); // true i.f.f. same elements in same order

구현 (경고 : 세부 정보는 버전에 따라 변경 될 수 있음)

목록의 요소 수가 List.of2 개 이하인 경우 요소는 특수 (내부) 클래스의 필드에 저장됩니다. 예는 2 개의 요소 (부분 소스)를 저장하는 목록입니다.

static final class List2<E> extends AbstractImmutableList<E> {
    private final E e0;
    private final E e1;

    List2(E e0, E e1) {
        this.e0 = Objects.requireNonNull(e0);
        this.e1 = Objects.requireNonNull(e1);
    }
}

그렇지 않으면 .NET과 유사한 방식으로 배열에 저장됩니다 Arrays.asList.

시간 및 공간 효율성

List.of필드 기반 (크기 <2)이다 구현은 어떤 작업이 약간 빠르게 수행한다. 예를 들어, size()배열 길이를 가져 오지 않고 상수를 반환 할 수 contains(E e)있으며 반복 오버 헤드가 필요하지 않습니다.

를 통해 수정할 수없는 목록을 생성 List.of하는 것도 더 빠릅니다. 위의 생성자를 2 개의 참조 할당 (임의의 요소에 대한 할당 포함)과 비교하여

Collections.unmodifiableList(Arrays.asList(...));

2 개의 목록과 다른 오버 헤드를 생성합니다. 공간 측면에서 UnmodifiableList래퍼와 약간의 동전 을 절약합니다 . 궁극적으로 HashSet동등한 비용 절감 이 더 설득력이 있습니다.


결론 시간 : List.of변경되지 않는 Arrays.asList목록을 원할 때 와 변경할 수있는 목록을 원할 때 사용합니다 (위 그림 참조).


1
이 답변이 왜 존재하는지 궁금한 사람들은 this를 참조 하십시오 .
user1803551

3
Arrays.asList완전히 변경할 수 없습니다. asList.add(1);던졌습니다 UnsupportedOperationException.
mapeters

"Null 적대적"은 그것을 표현하는 좋은 방법입니다. 나는 List.of사람들이 전화 contains하고 싶어 하고 NullPointerException에 놀라지 않을 시간을 거의 사용할 수 없습니다 .
Noumenon

14

List.ofArrays.asList 의 차이점을 요약 해 보겠습니다.

  1. List.of데이터 세트가 적고 변경되지 않은 Arrays.asList경우 가장 잘 사용할 수있는 반면, 크고 동적 데이터 세트의 경우 가장 잘 사용할 수 있습니다.

  2. List.of필드 기반 구현이 있기 때문에 오버 헤드 공간을 매우 적게 차지하고 고정 오버 헤드와 요소 별 기준 모두에서 더 적은 힙 공간을 사용합니다. Arrays.asList초기화하는 동안 힙에 더 많은 객체를 생성하기 때문에 더 많은 오버 헤드 공간 을 차지합니다.

  3. 에서 반환 된 컬렉션 List.of은 변경 불가능하므로 스레드로부터 안전하지만에서 반환 된 컬렉션 Arrays.asList은 변경 가능하며 스레드로부터 안전하지 않습니다. (불변 컬렉션 인스턴스는 일반적으로 가변 인스턴스보다 훨씬 적은 메모리를 사용합니다.)

  4. List.of허용하지 않는 동안 요소를 Arrays.asList허용 널 (null) 요소를.


2
"불변 컬렉션 인스턴스는 일반적으로 가변 인스턴스보다 훨씬 적은 메모리를 소비합니다." - 정말? 이것에 대해 좀 더 자세히 설명 해주시겠습니까? 안전하게 공유 할 수 있기 때문입니까, 아니면 인스턴스 자체를 어떻게 든 더 효율적으로 구현할 수 있다는 뜻입니까?
Hulk

1
@Hulk 응답자는 공간 효율성에 대해 옳습니다. : 스튜어트 마크 '이야기를 참조하십시오 youtu.be/q6zF3vf114M?t=49m48s
ZhekaKozlov

2
@ZhekaKozlov 일반적으로 사실 인 것처럼 보이지만 , 전자가 문자 그대로 배열을 둘러싼 래퍼라는 점을 감안할 때 Arrays.asListList.of에 대해 이야기 할 때 사실이라는 것은 매우 회의적입니다 . 최소한 OpenJDK의 구현 은 매우 작은 오버 헤드를 가지고있는 것으로 보입니다. 실제로 List.of전달 된 어레이의 복사본을 만들어야하므로 어레이 자체가 곧 GC가되지 않는 List.of한 훨씬 더 큰 메모리 공간을 가진 것처럼 보일 것 입니다.
크리스 헤이즈

4
적어도 @ChrisHayes List.of(x)그리고 List.of(x, y)그들은 모두에 배열을 할당하지 않기 때문에 더 효율적
ZhekaKozlov

2
@Hulk : List.of매번 새 목록을 반환하는 데 메서드가 필요 하지 않다는 것을 잊지 마십시오 . 이러한 목록에는 지정되지 않은 ID가 있으므로 JVM 수준에서 처리되는 캐싱 또는 중복 제거 또는 스칼라 화가있을 수 있습니다. 이 버전이 아니라면 아마도 다음 버전 일 것입니다. 계약에 의해 허용됩니다. 반대로 Array.asList결과 목록은 배열에서 변경 가능한보기이므로 모든 변경 사항을 양방향으로 반영하므로 전달하는 배열의 ID에 따라 다릅니다.
홀거

2

외에도 위의 답변에서 두 가지 모두에 대해 특정 작업이 있습니다 List::of와는 Arrays::asList차이가 :

+----------------------+---------------+----------+----------------+---------------------+
|      Operations      | SINGLETONLIST | LIST::OF | ARRAYS::ASLIST | JAVA.UTIL.ARRAYLIST |
+----------------------+---------------+----------+----------------+---------------------+
|          add         |             |       |              |          ✔️          |
+----------------------+---------------+----------+----------------+---------------------+
|        addAll        |             |       |              |          ✔️          |
+----------------------+---------------+----------+----------------+---------------------+
|         clear        |             |       |              |          ✔️          |
+----------------------+---------------+----------+----------------+---------------------+
|        remove        |             |       |              |          ✔️          |
+----------------------+---------------+----------+----------------+---------------------+
|       removeAll      |       ❗️       |        |        ❗️       |          ✔️          |
+----------------------+---------------+----------+----------------+---------------------+
|       retainAll      |       ❗️       |       |        ❗️        |          ✔️          |
+----------------------+---------------+----------+----------------+---------------------+
|      replaceAll      |             |       |        ✔️       |          ✔️          |
+----------------------+---------------+----------+----------------+---------------------+
|          set         |             |       |        ✔️       |          ✔️          |
+----------------------+---------------+----------+----------------+---------------------+
|         sort         |       ✔️       |        |        ✔️      |          ✔️          |
+----------------------+---------------+----------+----------------+---------------------+
|  remove on iterator  |             |       |              |          ✔️          |
+----------------------+---------------+----------+----------------+---------------------+
| set on list-iterator |             |       |        ✔️       |          ✔️          |
+----------------------+---------------+----------+----------------+---------------------+
  1. ✔️ 방법이 지원됨을 의미합니다.
  2. ❌는이 메서드를 호출하면 UnsupportedOperationException이 발생 함을 의미합니다.
  3. ❗️는 메서드의 인수가 변이를 일으키지 않는 경우에만 메서드가 지원됨을 의미합니다. 예를 들어 Collections.singletonList ( "foo"). retainAll ( "foo")은 괜찮지 만 Collections.singletonList ( "foo"). retainAll ( "bar") ) UnsupportedOperationException 발생

Collections :: singletonList Vs 에 대한 추가 정보 목록 ::의


1
자바 시험에 대한 답변
povis
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.