Java 9为列表引入了新的工厂方法List.of
:
List<String> strings = List.of("first", "second");
上一个选项和新选项之间有什么区别?也就是说,这之间有什么区别:
Arrays.asList(1, 2, 3);
还有这个:
List.of(1, 2, 3);
Java 9为列表引入了新的工厂方法List.of
:
List<String> strings = List.of("first", "second");
上一个选项和新选项之间有什么区别?也就是说,这之间有什么区别:
Arrays.asList(1, 2, 3);
还有这个:
List.of(1, 2, 3);
Answers:
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
允许null元素,而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
返回所传递数组的视图,因此对数组的更改也将反映在列表中。对于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.contains(Object o)
的javadoc:“抛出NullPointerException-如果指定的元素为null,并且此列表不允许null元素(可选)”。或者从界面的冗长介绍中,很少有人读到:“某些收集实现对它们可能包含的元素有限制”
List.of
确实返回了某种ImmutableList
类型,其实际名称只是一个非公开的实现细节。如果它是公开的并且有人List
再次将其抛弃,那么区别在哪里?与的区别在哪里Arrays.asList
,它返回一个非公共的List
实现,在尝试add
或时抛出异常remove
,或者返回的列表Collections.unmodifiableList
根本不允许任何修改?这都是关于List
界面中指定的合同的。自Java 1.2以来,带有可选方法的Collections接口始终是不纯正的OOP…
Arrays.asList
和之间的区别List.of
请参阅JavaDocs和Stuart Marks的演讲(或以前的版本)。
我将使用以下代码示例:
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(集合框架)的集合,因此允许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
其是基于场的(大小<2)实施方式中的一些操作速度稍快执行。作为示例,size()
可以在不获取数组长度的情况下返回常量,并且contains(E e)
不需要迭代开销。
通过构造一个不可修改的列表List.of
也更快。将上面的构造函数与2个引用分配(甚至是任意数量的元素的引用分配)进行比较,以得出
Collections.unmodifiableList(Arrays.asList(...));
这将创建2个列表以及其他开销。就空间而言,您可以节省UnmodifiableList
包装纸和几分钱。最终,HashSet
同等成本的节省更具说服力。
结论时间:List.of
当您希望列表不变时,以及Arrays.asList
想要列表可以更改时使用(如上所示)。
Arrays.asList
不是完全可变的。asList.add(1);
抛出一个UnsupportedOperationException
。
List.of
任何时候人们都想打电话contains
给NullPointerException感到惊讶。
让我们总结一下List.of和Arrays.asList之间的区别
List.of
数据集较少且不变时,Arrays.asList
最好使用此方法;而动态数据集较大时,最好使用。
List.of
占用很少的开销空间,因为它具有基于字段的实现,并且在固定开销和每个元素的基础上都消耗较少的堆空间。而Arrays.asList
需要更多开销的空间,因为当初始化它会在堆更多的对象。
返回的集合List.of
是不可变的,因此是线程安全的,而返回的集合Arrays.asList
是可变的,而不是线程安全的。(不可变集合实例通常比可变实例消耗更少的内存。)
List.of
不允许使用null元素,而Arrays.asList
允许使用null元素。
Arrays.asList
vs 时是否正确List.of
,因为前者实际上只是数组的包装。至少OpenJDK的实现似乎开销很小。实际上,List.of
需要复制任何传入的数组的副本,因此,除非该数组本身即将被GC淘汰,否则似乎List.of
占用的内存空间要大得多。
List.of(x)
和List.of(x, y)
更有效,因为他们根本就不分配阵列
List.of
每次都不需要方法返回新列表。这些列表具有未指定的标识,因此可能在JVM级别上进行了缓存,重复数据删除或标量处理。如果不在此版本中,则可能在下一个版本中。合同允许的。相反,Array.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 | ❌ | ❌ | ✔️ | ✔️ |
+----------------------+---------------+----------+----------------+---------------------+