当前位置: 首页 > 面试题库 >

Java 9收集工厂的用法

卞坚成
2023-03-14
问题内容

在List.of()或Collections.emptyList()和List.of(…)或Collections.unmodifiableList()给出的评论和答案的背景下,
我提出了以下两个经验法则(也适用于Set以及相应的Map工厂)。

  1. 不要取代所有事件

继续使用Collections.emptyList()以提高可读性,例如在初始化惰性字段成员时,例如:

class Bean {
  private List<Bean> beans = Collection.emptyList();
  public List<Bean> getBeans() {
    if (beans == Collections.EMPTY_LIST) { beans = new ArrayList<>(); }
    return beans;
  }
}
  1. 使用新工厂作为方法参数构建

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.ofMap.of结构随机化其迭代顺序。的迭代顺序HashSetHashMap未定义,但在实践中被证明是相对稳定的。代码可能会无意间依赖迭代顺序。切换到新的集合工厂可能会使旧代码暴露于迭代顺序依赖性,从而掩盖潜在的错误。

禁止空值。 新的集合禁止空完全,而常见的非并发集合(ArrayListHashMap)使他们。

序列化格式。
新集合具有与旧集合不同的序列化格式。如果集合已序列化,或者存储在其他已序列化的类中,则序列化的输出将有所不同。这可能是问题,也可能不是问题。但是,如果您希望与其他系统进行互操作,则可能会出现问题。特别是,如果将新集合的序列化形式传输到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。

重复。
新工厂SetMap工厂拒绝重复的元素和密钥。如果要使用常量列表初始化集合,通常这不是问题。确实,如果常量列表中有重复项,则可能是一个错误。这可能是一个问题,当允许调用者传递元素的集合或数组(例如,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

  • 工厂-创建对象而不向客户机公开实例化逻辑,并通过公共接口引用新创建的对象。是工厂方法的简化版本 工厂方法-定义一个创建对象的接口,但让子类决定实例化哪个类,并通过公共接口引用新创建的对象。 抽象工厂-提供了创建相关对象家族的接口,而无需显式指定它们的类。 null