在List.of()或Collections.emptyList()和List.of(…)或Collections.unmodifiableList()给出的评论和答案的背景下,
我提出了以下两个经验法则(也适用于Set
以及相应的Map
工厂)。
继续使用Collections.emptyList()
以提高可读性,例如在初始化惰性字段成员时,例如:
class Bean {
private List<Bean> beans = Collection.emptyList();
public List<Bean> getBeans() {
if (beans == Collections.EMPTY_LIST) { beans = new ArrayList<>(); }
return beans;
}
}
List.of()
调用带有List
参数的可执行文件时,请使用新的工厂和变量作为快速且类型较少的版本。这是我目前的替换模式:
Collections.emptyList() --> List.of()
Collections.singletonList(a) --> List.of(a)
Arrays.asList(a, ..., z) --> List.of(a, ..., z)
在的虚构用法中Collections.indexOfSubList
,以下几行
Collections.indexOfSubList(Arrays.asList(1, 2, 3), Collections.emptyList());
Collections.indexOfSubList(Arrays.asList(1, 2, 3), Collections.singletonList(1));
Collections.indexOfSubList(Arrays.asList(1, 2, 3), Arrays.asList(1));
Collections.indexOfSubList(Arrays.asList(1, 2, 3), Arrays.asList(2, 3));
Collections.indexOfSubList(Arrays.asList(1, 2, 3), Arrays.asList(1, 2, 3));
会读
Collections.indexOfSubList(List.of(1, 2, 3), List.of());
Collections.indexOfSubList(List.of(1, 2, 3), List.of(1));
Collections.indexOfSubList(List.of(1, 2, 3), List.of(1));
Collections.indexOfSubList(List.of(1, 2, 3), List.of(2, 3));
Collections.indexOfSubList(List.of(1, 2, 3), List.of(1, 2, 3));
你不同意吗?
通常,对于没有新代码的新工厂来说,使用新工厂是安全的,因为不存在依赖于现有集合行为的新代码。
新收集工厂没有直接替换使用现有API初始化收集的代码的原因有很多。显而易见,不变性是最突出的原因之一。如果您以后需要修改集合,那么它显然不能一成不变!但是,还有其他原因,其中一些原因非常微妙。
有关使用新API替换现有API的示例,请参见JDK-8134373。审阅主题在这里:Part1Part2。
这是问题的摘要。
阵列包装与复制。
有时您有一个数组,例如varargs参数,并且想要将其作为列表处理。有时这Arrays.asList
是最合适的方法,因为它只是包装器。相比之下,List.of
创建一个副本可能会很浪费。另一方面,调用方仍然具有包装后的数组的句柄并可以对其进行修改,这可能是一个问题,因此有时您需要支付复制它的费用,例如,如果您想保留对数组的引用。在实例变量中列出。
哈希收集迭代顺序。
新的Set.of
和Map.of
结构随机化其迭代顺序。的迭代顺序HashSet
和HashMap
未定义,但在实践中被证明是相对稳定的。代码可能会无意间依赖迭代顺序。切换到新的集合工厂可能会使旧代码暴露于迭代顺序依赖性,从而掩盖潜在的错误。
禁止空值。 新的集合禁止空完全,而常见的非并发集合(ArrayList
,HashMap
)使他们。
序列化格式。
新集合具有与旧集合不同的序列化格式。如果集合已序列化,或者存储在其他已序列化的类中,则序列化的输出将有所不同。这可能是问题,也可能不是问题。但是,如果您希望与其他系统进行互操作,则可能会出现问题。特别是,如果将新集合的序列化形式传输到Java
8 JVM,则它将无法反序列化,因为Java 8上不存在新类。
严格的Mutator方法行为。
新的集合是不可变的,因此,当然,它们UnsupportedOperationException
在调用mutator方法时会抛出。但是,在某些极端情况下,所有集合的行为都不相同。例如,
Collections.singletonList("").addAll(Collections.emptyList())
什么都不做,而
List.of("").addAll(Collections.emptyList())
将抛出UOE。通常,新集合和不可修改的包装程序始终严格要求在对mutator方法的任何调用上都抛出UOE,即使不会发生实际的突变。其他不可变的集合(例如from
Collections.empty*
和)Collections.singleton*
,仅在发生实际突变时才会抛出UOE。
重复。
新工厂Set
和Map
工厂拒绝重复的元素和密钥。如果要使用常量列表初始化集合,通常这不是问题。确实,如果常量列表中有重复项,则可能是一个错误。这可能是一个问题,当允许调用者传递元素的集合或数组(例如,varags)时。如果调用方传递重复项,则现有的API将默默地省略重复项,而新工厂将抛出IllegalArgumentException
。这是一种行为变化,可能会影响呼叫者。
这些问题都不是致命的问题,但是它们是在改进现有代码时应注意的行为差异。不幸的是,这意味着用新的回收工厂大量替换现有呼叫可能是不明智的。可能有必要在每个站点进行一些检查,以评估行为更改的任何潜在影响。
在Java 9中,新的工厂方法被添加到,和接口来创建不可变的实例。 这些工厂方法是便捷的工厂方法,以较简洁的方式创建集合。 旧的方式创建集合 执行上面示例代码,得到以下结果 - 新方法 使用java 9,以下方法将被添加到,和接口以及它们的重载对象。 注意事项 对于和接口,方法重载为到个参数,另一个使用参数。 对于接口,方法重载为有到个参数。 如果接口的参数超过个,则可以使用方法接受参数。 创建集
Java9提供了创建不可变列表的便利工厂方法。最后,创建列表非常简单: 但是这种方法有12个重载版本,11个有0到10个元素,一个有var args。 和的情况也是如此。 既然有一个var-args方法,那么有额外的11个方法有什么意义呢? 我认为var args创建一个数组,所以其他11个方法可以跳过额外对象的创建,在大多数情况下,0-10个元素就可以了。还有其他原因吗?
在Java9中,我们有方便的工厂方法来创建和实例化不可变的List、Set和map。
使用Java 9,新的工厂方法被添加到List,Set和Map接口以创建不可变实例。 这些工厂方法是便利工厂方法,以较简洁和简洁的方式创建集合。 创建集合的旧方法 import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import j
可能是一个简单的方法, 我想要的是:我有一个监听传入连接的tcp服务器。当客户连接时,我希望以某种方式得到通知。TcpNetServerConnectionFactory内部有这样的信息"接受的连接..."。 有一个TcpConnectionSupport类,但是我找不到如何使用它的方法。我正在寻找类似的用户模式。 有什么办法可以做到吗?