Java 9,Set.of()和Map.of()varargs重载

Java 9,Set.of()和Map.of()varargs重载,java,collections,java-9,Java,Collections,Java 9,我正在研究不可变集合的工厂方法。 我看到Set.of()方法有10个varargs重载(与Map.of()相同)。我真不明白为什么有这么多。最后还是调用函数ImmutableCollections.SetN(elements) 在文档中,我发现: 虽然这在API中引入了一些混乱,但它避免了由varargs调用引起的数组分配、初始化和垃圾收集开销 杂乱无章的东西真的值得性能提升吗?如果是,那么理想情况下是否会为任何N元素创建一个单独的方法?在调用该方法时,这可能会改变。例如,它可以创建一个只有三个

我正在研究
不可变
集合的工厂方法。 我看到
Set.of()
方法有10个varargs重载(与
Map.of()
相同)。我真不明白为什么有这么多。最后还是调用函数
ImmutableCollections.SetN(elements)

在文档中,我发现:

虽然这在API中引入了一些混乱,但它避免了由varargs调用引起的数组分配、初始化和垃圾收集开销

杂乱无章的东西真的值得性能提升吗?如果是,那么理想情况下是否会为任何
N
元素创建一个单独的方法?

在调用该方法时,这可能会改变。例如,它可以创建一个只有三个元素的
集合
,4等等

也不是所有的元素都委托给
SetN
——具有零、一和两个元素的元素具有
ImmutableCollections.Set0
ImmutableCollections.Set1
ImmutableCollections.Set2


或者你可以阅读关于这个的实际问题。。。阅读
Stuart Marks
在该问题上的评论,因为他是这些收藏的创造者

我想这取决于您使用的API的范围。当谈论那些不可变的类时,你谈论的是作为jdk一部分包含的东西;所以范围很广

所以你有:

  • 一方面,这些不可变类可能会被应用程序使用,在应用程序中,每一位都会计数(并且在分配/释放过程中浪费了每一纳秒)
  • 另一方面,没有这些需求的应用程序不会受到负面影响
  • 唯一“消极”的一面是该API的实现者需要处理更多的混乱,因此它会影响可维护性(但在这种情况下不是什么大问题)

  • 如果你在实现你自己的东西,我不会太在意(但对varargs参数要小心),除非你真的需要担心那些额外的比特(和额外的性能等)。

    这方面的某些方面可能是未来的证明

    如果您开发一个API,您需要注意方法签名将如何更改,因此如果我们

    public class API {
      public static final <T> Set<T> of(T... elements) { ... }
    }
    

    然后,我们可以分析和查看真实世界的使用模式,如果我们看到4 arg表单和基准的显著使用率显示有合理的性能增益,那么在这一点上,在幕后,我们更改了方法impl,每个人都获得了胜利。。。不需要重新编译

    我想他们希望这些方法能得到大量的使用。哇。你不能为“任何
    N
    元素”创建一个方法,因为
    N
    可能是一个非常大的数字:)@C-Otto,我当然知道,我只是问这是否有助于提高性能:)是的,你已经列举了原因。@GhostCat那是因为Sotirios当时在线,别忘了,在事实发生后添加(T)的
    不会改变已经编译好的代码。更糟糕的是,如果仍然使用较旧版本的JDK进行编译,它甚至不会改进未来的代码。噢,奇怪的Stackoverflow世界。就在上周,同样的问题被提出,并在1分钟内以副本的形式结案。这个版本得到了20票的支持和很好的回答。幸运的是,还需要注意的是,varargs方法需要创建数组的防御副本以保证不变性,因此即使3-10个arity重载中的一个最终使用数组
    SetN
    ,它的构造也可能更便宜。将数组创建代码放在一个中心位置而不是每个调用方可以减少总体代码大小,
    Set0
    更适合于
    Set1
    Set2
    。@Holger关于第二个参数-你是说创建数组副本可能比填充3个或更多字段的对象更便宜吗?不,我是说如果应用程序代码调用varargs方法,应用程序创建数组,jre代码必须为
    ListN
    创建一个防御副本(对于
    SetN
    ,无论如何都将填充一个新数组)。但是如果应用程序调用一个十参数方法,它不会创建一个数组,只有jre代码创建一个数组,而不需要副本。因此,即使没有
    Set10
    ,调用ten-arg方法也可以比varargs方法更快地创建
    ListN
    /
    SetN
    。这一机会尚未得到利用。
    public class API {
      public static final <T> Set<T> of(T first) { ... }
      public static final <T> Set<T> of(T first, T... others) { ... }
    }
    
    public class API {
      public static final <T> Set<T> of(T first) { ... }
      @Deprecated public static final <T> Set<T> of(T... elements) { ... }
      public static final <T> Set<T> of(T first, T... others) { ... }
    }
    
    public class API {
      private static final <T> Set<T> internalOf(T... elements) { ... }
      public static final <T> Set<T> of(T first) { return internalOf(first); }
      public static final <T> Set<T> of(T first, T second) { return internalOf(first, second); }
      ...
      public static final <T> Set<T> of(T t1, T t2, T t3, T t4, T t5, T... rest) { ... }
    }