List.of() or Collections.emptyList()List.of(...) or Collections.unmodifiableList()给出的评论和答案的上下文中,我提出了以下两个经验法则(相应地,它们也适用于SetMap工厂)。

  • 不要替换所有出现的

  • 继续使用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。审阅主题在这里:Part1 Part2

    这是问题的摘要。

    数组包装与复制。 有时您有一个数组,例如varargs参数,并且您希望将其作为列表进行处理。有时候Arrays.asList在这里是最合适的,因为它只是一个包装器。相比之下,List.of创建一个副本,这可能很浪费。另一方面,调用方仍然具有包装后的数组的句柄并可以对其进行修改,这可能是一个问题,因此有时您需要支付复制它的费用,例如,如果您想要保留对数组的引用。在实例变量中列出。

    哈希集合迭代顺序。 新的Set.ofMap.of结构使它们的迭代顺序随机化。 HashSetHashMap的迭代顺序是不确定的,但实际上它是相对稳定的。代码可能会无意间依赖迭代顺序。切换到新的收集工厂可能会使旧代码暴露于迭代顺序依赖性,从而掩盖潜在的错误。

    禁止使用Null。 新集合完全禁止使用空值,而常见的非并行集合(ArrayListHashMap)允许它们。

    序列化格式。 新集合具有与旧集合不同的序列化格式。如果集合已序列化,或者存储在其他已序列化的类中,则序列化的输出将有所不同。这可能是问题,也可能不是问题。但是,如果您希望与其他系统进行互操作,则可能会出现问题。特别是,如果将新集合的序列化形式传输到Java 8 JVM,它将无法反序列化,因为新类在Java 8上不存在。

    严格的Mutator方法行为。 新集合是不可变的,因此,当调用mutator方法时,它们当然会抛出UnsupportedOperationException。但是,在某些极端情况下,所有集合的行为都不相同。例如,

        Collections.singletonList("").addAll(Collections.emptyList())
    

    什么都不做,而
        List.of("").addAll(Collections.emptyList())
    

    将抛出UOE。通常,新集合和不可修改的包装程序始终严格要求在对mutator方法的任何调用上都抛出UOE,即使不会发生实际的突变。其他不可变集合(例如Collections.empty*Collections.singleton*的集合)仅在发生实际突变时才会抛出UOE。

    重复项。 新的SetMap工厂拒绝重复的元素和键。如果要使用常量列表初始化集合,通常这不是问题。确实,如果常量列表中有重复项,则可能是一个错误。这可能是一个问题,当允许调用者传递元素的集合或数组(例如varags)时。如果调用方传递重复项,则现有的API将默默地省略重复项,而新工厂将抛出IllegalArgumentException。这是一种行为变化,可能会影响调用者。

    这些问题都不是致命的问题,但是它们是在改进现有代码时应注意的行为差异。不幸的是,这意味着用新的回收工厂大量替换现有调用可能是不明智的。可能有必要在每个站点进行一些检查,以评估行为更改的任何潜在影响。

    10-01 23:58
    查看更多