列表之间有什么区别。和Arrays.asList?

Java 9为列表引入了新的工厂方法List.of:

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

以前的选择和新的选择有什么不同?也就是说,这两者之间的区别是什么

Arrays.asList(1, 2, 3);

这:

List.of(1, 2, 3);
120038 次浏览

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不允许:

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

contains对空值的处理方式不同:

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]

让我们总结一下List.ofarrays . aslist之间的区别

  1. List.of最好在数据集较少且不变的情况下使用,而Arrays.asList最好在数据集较大且动态的情况下使用。

  2. List.of占用非常少的开销空间,因为它具有基于字段的实现,并且在固定开销和每个元素的基础上消耗更少的堆空间。而Arrays.asList占用更多的开销空间,因为在初始化时它会在堆中创建更多的对象。

  3. List.of返回的集合是不可变的,因此是线程安全的,而Arrays.asList返回的集合是可变的,不线程安全。 (不可变集合实例通常比可变集合实例消耗更少的内存)

  4. List.of不允许null元素,而Arrays.asList允许null元素。

Arrays.asListList.of之间的区别

参见Stuart Marks的JavaDocs和这个说话(或它的以前版本)。

我将使用以下代码示例:

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

结构不变性(或:不可修改性)

任何试图改变List.of在结构上尝试都会导致UnsupportedOperationException。这包括添加删除等操作。但是,您可以更改列表中对象的内容(如果对象不是不可变的),因此列表不是“完全不可变的”。

对于用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(集合框架)中的一个集合,它允许nulls。

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

序列化形式

由于在Java 9中引入了List.of,并且通过此方法创建的列表有自己的(二进制)序列化形式,因此不能在早期JDK版本(没有二进制兼容性)上反序列化它们。但是,例如,您可以使用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.of列表中的元素数量为2或更少,则元素存储在专门化(内部)类的字段中。一个例子是存储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的方式存储在数组中。

时空效率

基于字段的List.of实现(size<2)在某些操作上执行得稍微快一些。例如,size()可以返回一个常量而不获取数组长度,并且contains(E e)不需要迭代开销。

通过List.of构造一个不可修改的列表也更快。将上面的构造函数与两个引用赋值(甚至任意数量的元素)进行比较

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

这会创建2个列表加上其他开销。在空间方面,您节省了UnmodifiableList包装器和一些便士。最终,在HashSet中的节省是更令人信服的。


总结时间:当你想要一个不会改变的列表时使用List.of,当你想要一个可以改变的列表时使用Arrays.asList(如上所示)。

除了上面的答案,还有一些List::ofArrays::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 .retainAll(“foo”)(“酒吧”)抛出 UnsupportedOperationException李> < /方式

关于集合::singletonList Vs. List::of的更多信息

数组。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
}

列表。(1,2,3)的;

不可更改(Java 9)/不可更改(Java 11) 列表将被创建:

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
}