List.of 和 Arrays.asList 有什么区别?

新手上路,请多包涵

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

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

以前的选项和新选项有什么区别?也就是说,这之间有什么区别:

 Arrays.asList(1, 2, 3);

和这个:

 List.of(1, 2, 3);

原文由 user5908494 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 756
2 个回答

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]

原文由 ZhekaKozlov 发布,翻译遵循 CC BY-SA 4.0 许可协议

Arrays.asListList.of 之间的区别

请参阅 JavaDocs 和 Stuart Marks 的这次 演讲(或它的早期版本)。

我将使用以下代码示例:

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

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

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

这与使用 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 版本上反序列化(无 _二进制兼容性_)。但是,例如,您可以使用 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() 可以在不获取数组长度的情况下返回常量, contains(E e) 不需要迭代开销。

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

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

这会创建 2 个列表以及其他开销。在空间方面,您节省了 UnmodifiableList 包装纸和一些便士。最终,等效于 HashSet 的节省更具说服力。


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

原文由 user1803551 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题