通常,对于没有新代码的新工厂来说,使用新工厂是安全的,因为不存在依赖于现有集合行为的新代码。
新收集工厂没有直接替换使用现有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。这是一种行为变化,可能会影响呼叫者。
这些问题都不是致命的问题,但是它们是在改进现有代码时应注意的行为差异。不幸的是,这意味着用新的回收工厂大量替换现有呼叫可能是不明智的。可能有必要在每个站点进行一些检查,以评估行为更改的任何潜在影响。



