List.of 和 Arrays.asList 有什么区别?
What is the difference between List.of and Arrays.asList?
Java 9 为列表引入了新的工厂方法,List.of
:
List<String> strings = List.of("first", "second");
旧选项和新选项有什么区别?也就是这个有什么区别:
Arrays.asList(1, 2, 3);
还有这个:
List.of(1, 2, 3);
Arrays.asList
returns 一个可变列表,而 List.of
返回的列表是 immutable:
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
不允许:
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
returns 传递数组的视图,因此对数组的更改也会反映在列表中。 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]
总结一下List.of和Arrays.asList
的区别
List.of
最适合数据集较少且不变的情况,而Arrays.asList
最适合大数据集和动态数据集的情况。
List.of
开销非常小 space 因为它具有基于字段的实现并且消耗更少的堆 space,无论是在固定开销还是在每个元素的基础。而 Arrays.asList
需要更多开销 space 因为在初始化时它会在堆中创建更多对象。
List.of
返回的集合是不可变的,因此是线程安全的,而 Arrays.asList
返回的集合是可变的,不是线程安全的。
(不可变集合实例通常比可变集合实例消耗更少的内存。)
List.of
不允许 null 元素,而 Arrays.asList
允许 null 元素.
Arrays.asList
and List.of
之间的区别
请参阅 Stuart Marks 的 JavaDocs and this talk(或它的早期版本)。
我将使用以下代码示例:
List<Integer> listOf = List.of(...);
List<Integer> asList = Arrays.asList(...);
List<Integer> unmodif = Collections.unmodifiableList(asList);
结构不变性(或:不可修改性)
任何结构上改变List.of
的尝试都会导致UnsupportedOperationException
。这包括 add、set 和 remove 等操作。但是,您可以更改列表中对象的内容(如果对象不是不可变的),因此列表不是 "completely immutable".
这与使用 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.of
和自 Java 1.5 以来的任何集合都不允许 null
作为元素。尝试将 null
作为元素甚至查找传递将导致 NullPointerException
.
由于 Arrays.asList
是 1.2(集合框架)的集合,它允许 null
s。
listOf.contains(null); // NullPointerException
unmodif.contains(null); // allowed
asList.contains(null); // allowed
连载形式
由于 List.of
已在 Java 9 中引入,并且通过此方法创建的列表具有自己的(二进制)序列化形式,因此无法在早期的 JDK 版本上反序列化(没有 二进制兼容性 )。但是,您可以 de/serialize 和 JSON,例如。
身份
Arrays.asList
内部调用 new ArrayList
,保证引用不等。
List.of
取决于内部实现。 returned 实例可以具有引用相等性,但由于不能保证您不能依赖它。
asList1 == asList2; // false
listOf1 == listOf2; // true or false
值得一提的是,如果列表以相同的顺序包含相同的元素,则列表是相等的(通过 List.equals
),无论它们是如何创建的或它们支持什么操作。
asList.equals(listOf); // true i.f.f. same elements in same order
实施(警告:细节可能会随着版本的不同而改变)
如果 List.of
列表中的元素数为 2 个或更少,则元素存储在专用(内部)class 的字段中。一个例子是存储 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);
}
}
否则它们将以类似于 Arrays.asList
的方式存储在数组中。
时间和Space效率
基于字段(大小<2)的 List.of
实现在某些操作上执行速度稍快。例如,size()
可以 return 一个常量而无需获取数组长度,而 contains(E e)
不需要迭代开销。
通过List.of
构建一个不可修改的列表也更快。将上面的构造函数与 2 个引用赋值(甚至是任意数量元素的一个)进行比较
Collections.unmodifiableList(Arrays.asList(...));
这会创建 2 个列表以及其他开销。就 space 而言,您可以节省 UnmodifiableList
包装纸和一些便士。最终,HashSet
等值的节省更具说服力。
结论时间:当你想要一个不变的列表时使用List.of
,当你想要一个可以更改的列表时使用Arrays.asList
(如上所示)。
除了上述答案之外,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 | ❌ | ❌ | ✔️ | ✔️ |
+----------------------+---------------+----------+----------------+---------------------+
- ✔️表示支持该方法
- ❌ 表示调用这个方法会抛出一个
UnsupportedOperationException
- ❗️ 表示仅当方法的参数支持时才支持该方法
不会引起突变,例如
Collections.singletonList("foo").retainAll("foo") 可以,但是
Collections.singletonList("foo").retainAll("bar") 抛出一个
UnsupportedOperationException
Arrays.asList(1, 2, 3);
将创建一个 固定大小 列表:
public static void main(String[] args) {
List<Integer> asList = Arrays.asList(1, 2, 3, 4, 5);
asList.add(6); // java.lang.UnsupportedOperationException
asList.remove(0); // java.lang.UnsupportedOperationException
asList.set(0, 0); // allowed
}
List.of(1, 2, 3);
A Immutable(Java 9)/Unmodifiable(Java 11) List 将被创建:
public static void main(String[] args) {
List<Integer> listOf = List.of(1, 2, 3, 4, 5);
listOf.add(6); // java.lang.UnsupportedOperationException
listOf.remove(0); // java.lang.UnsupportedOperationException
listOf.set(0, 0); // java.lang.UnsupportedOperationException
}
Java 9 为列表引入了新的工厂方法,List.of
:
List<String> strings = List.of("first", "second");
旧选项和新选项有什么区别?也就是这个有什么区别:
Arrays.asList(1, 2, 3);
还有这个:
List.of(1, 2, 3);
Arrays.asList
returns 一个可变列表,而 List.of
返回的列表是 immutable:
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
不允许:
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
returns 传递数组的视图,因此对数组的更改也会反映在列表中。 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]
总结一下List.of和Arrays.asList
的区别List.of
最适合数据集较少且不变的情况,而Arrays.asList
最适合大数据集和动态数据集的情况。List.of
开销非常小 space 因为它具有基于字段的实现并且消耗更少的堆 space,无论是在固定开销还是在每个元素的基础。而Arrays.asList
需要更多开销 space 因为在初始化时它会在堆中创建更多对象。List.of
返回的集合是不可变的,因此是线程安全的,而Arrays.asList
返回的集合是可变的,不是线程安全的。 (不可变集合实例通常比可变集合实例消耗更少的内存。)List.of
不允许 null 元素,而Arrays.asList
允许 null 元素.
Arrays.asList
and List.of
之间的区别
请参阅 Stuart Marks 的 JavaDocs and this talk(或它的早期版本)。
我将使用以下代码示例:
List<Integer> listOf = List.of(...);
List<Integer> asList = Arrays.asList(...);
List<Integer> unmodif = Collections.unmodifiableList(asList);
结构不变性(或:不可修改性)
任何结构上改变List.of
的尝试都会导致UnsupportedOperationException
。这包括 add、set 和 remove 等操作。但是,您可以更改列表中对象的内容(如果对象不是不可变的),因此列表不是 "completely immutable".
这与使用 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.of
和自 Java 1.5 以来的任何集合都不允许 null
作为元素。尝试将 null
作为元素甚至查找传递将导致 NullPointerException
.
由于 Arrays.asList
是 1.2(集合框架)的集合,它允许 null
s。
listOf.contains(null); // NullPointerException
unmodif.contains(null); // allowed
asList.contains(null); // allowed
连载形式
由于 List.of
已在 Java 9 中引入,并且通过此方法创建的列表具有自己的(二进制)序列化形式,因此无法在早期的 JDK 版本上反序列化(没有 二进制兼容性 )。但是,您可以 de/serialize 和 JSON,例如。
身份
Arrays.asList
内部调用 new ArrayList
,保证引用不等。
List.of
取决于内部实现。 returned 实例可以具有引用相等性,但由于不能保证您不能依赖它。
asList1 == asList2; // false
listOf1 == listOf2; // true or false
值得一提的是,如果列表以相同的顺序包含相同的元素,则列表是相等的(通过 List.equals
),无论它们是如何创建的或它们支持什么操作。
asList.equals(listOf); // true i.f.f. same elements in same order
实施(警告:细节可能会随着版本的不同而改变)
如果 List.of
列表中的元素数为 2 个或更少,则元素存储在专用(内部)class 的字段中。一个例子是存储 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);
}
}
否则它们将以类似于 Arrays.asList
的方式存储在数组中。
时间和Space效率
基于字段(大小<2)的 List.of
实现在某些操作上执行速度稍快。例如,size()
可以 return 一个常量而无需获取数组长度,而 contains(E e)
不需要迭代开销。
通过List.of
构建一个不可修改的列表也更快。将上面的构造函数与 2 个引用赋值(甚至是任意数量元素的一个)进行比较
Collections.unmodifiableList(Arrays.asList(...));
这会创建 2 个列表以及其他开销。就 space 而言,您可以节省 UnmodifiableList
包装纸和一些便士。最终,HashSet
等值的节省更具说服力。
结论时间:当你想要一个不变的列表时使用List.of
,当你想要一个可以更改的列表时使用Arrays.asList
(如上所示)。
除了上述答案之外,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 | ❌ | ❌ | ✔️ | ✔️ |
+----------------------+---------------+----------+----------------+---------------------+
- ✔️表示支持该方法
- ❌ 表示调用这个方法会抛出一个 UnsupportedOperationException
- ❗️ 表示仅当方法的参数支持时才支持该方法 不会引起突变,例如 Collections.singletonList("foo").retainAll("foo") 可以,但是 Collections.singletonList("foo").retainAll("bar") 抛出一个 UnsupportedOperationException
Arrays.asList(1, 2, 3);
将创建一个 固定大小 列表:
public static void main(String[] args) {
List<Integer> asList = Arrays.asList(1, 2, 3, 4, 5);
asList.add(6); // java.lang.UnsupportedOperationException
asList.remove(0); // java.lang.UnsupportedOperationException
asList.set(0, 0); // allowed
}
List.of(1, 2, 3);
A Immutable(Java 9)/Unmodifiable(Java 11) List 将被创建:
public static void main(String[] args) {
List<Integer> listOf = List.of(1, 2, 3, 4, 5);
listOf.add(6); // java.lang.UnsupportedOperationException
listOf.remove(0); // java.lang.UnsupportedOperationException
listOf.set(0, 0); // java.lang.UnsupportedOperationException
}