List.of和Arrays.asList有什么区别?
Java 9引入了新的Collection Factory方法List.of
:
List<String> strings = List.of("first", "second");
那么,以前的和新的选择有什么区别? 也就是说,这有什么区别:
Arrays.asList(1, 2, 3);
和这个:
List.of(1, 2, 3);
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
Arrays.asList
允许null元素,而List.of
不允许:
List<Integer> list = Arrays.asList(1, 2, null); // OK
List<Integer> list = List.of(1, 2, null); // Fails with a NullPointerException
contains
方法的行为与空值不同:
List<Integer> list = Arrays.asList(1, 2, 3);
list.contains(null); // Return false
List<Integer> list = List.of(1, 2, 3);
list.contains(null); // Throws 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]
Arrays.asList
和List.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
同样,更改支持数组(如果您持有它)将更改列表。
结构不可变性带来许多与防御性编码,并发性和安全性有关的副作用,这超出了本答案的范围。
没有敌意
自Java 1.5以来, List.of
和任何集合都不允许null
作为元素。 尝试传递null
作为一个元素甚至查找将导致NullPointerException
。
由于Arrays.asList
是一个来自1.2(集合框架)的集合,它允许null
。
listOf.contains(null); // NullPointerException
unmodif.contains(null); // allowed
asList.contains(null); // allowed
序列化的形式
由于List.of
已在Java 9中引入,并且由此方法创建的列表具有其自己的(二进制)序列化表单,因此它们不能在早期的JDK版本上反序列化(无二进制兼容性)。 但是,例如,您可以使用JSON进行de / serialize。
身分
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
类似的方式存储在数组中。
时间和空间效率
基于字段(大小<2)的List.of
实现在某些操作上执行速度稍快。 作为示例, size()
可以返回一个常量而不需要获取数组长度,并且contains(E e)
不需要迭代开销。
通过List.of
构建一个不可修改的列表也更快。 将上面的构造函数与2个引用赋值(甚至是任意数量的元素赋值)进行比较
Collections.unmodifiableList(Arrays.asList(...));
这会创建2个列表以及其他开销。 在空间方面,你保存了UnmodifiableList
包装器加上一些便士。 最终, HashSet
等价物的节省更具说服力。
结论时间:使用List.of
当你想不改变和列表Arrays.asList
当你想,可以改变(如上图所示)的列表。
让我们总结一下List.of和Arrays.asList之间的区别
当数据集较少且不变时, List.of
可以得到最佳使用,而Arrays.asList
可以在大型和动态数据集的情况下使用得最好。
List.of
占用非常少的开销空间,因为它具有基于字段的实现并消耗更少的堆空间,无论是在固定开销还是基于每个元素的情况下。 而Arrays.asList
需要更多的开销空间,因为初始化时它会在堆中创建更多的对象。
List.of
返回的List.of
是不可变的,因此线程安全,而Arrays.asList
返回的Arrays.asList
是可变的,而不是线程安全的。 (不可变集合实例通常消耗的内存比它们的可变对象少得多。)
List.of
不允许空元素,而Arrays.asList
允许空元素。
上一篇: What is the difference between List.of and Arrays.asList?
下一篇: Cannot install packages using node package manager in Ubuntu