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

我正在研究Immutable集合的工厂方法。 我看到Set.of()方法有10个varargs重载( Map.of()相同)。 我真的不明白为什么会这么多。 最后,无论如何都会调用函数ImmutableCollections.SetN(elements)

在文档中我发现了这个:

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

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

无论如何,此方法被调用 – 这可能会改变。 例如,它可能会创建一个只有三个元素的集合,4等等。

也不是所有的都委托给SetN – 那些有零,一和两个元素的实际类有ImmutableCollections.Set0ImmutableCollections.Set1ImmutableCollections.Set2

或者您可以阅读有关此问题的实际问题…… 在这里阅读Stuart Marks在该问题中的评论 – 他是创建这些collections的人。

这方面的某些方面可能是未来certificate的一种forms。

如果你发展了一个API,你需要注意方法签名将如何改变,所以如果我们有

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

我们可以说varargs已经足够好了……除了varargs 强制分配一个对象数组,这虽然相当便宜,但确实会影响性能。 例如,参见此微基准测试 ,显示切换到varargsforms时无操作日志记录(即日志级别低于可记录)的吞吐量损失50%。

好的,所以我们做了一些分析并说最常见的情况是单身,所以我们决定重构……

 public class API { public static final  Set of(T first) { ... } public static final  Set of(T first, T... others) { ... } } 

Ooops …这不是二进制兼容的…它的源兼容,但不兼容二进制…为了保持二进制兼容性,我们需要保留以前的签名,例如

 public class API { public static final  Set of(T first) { ... } @Deprecated public static final  Set of(T... elements) { ... } public static final  Set of(T first, T... others) { ... } } 

呃… IDE代码完成现在一团糟……再加上如何创建一组数组? (如果我使用列表可能更相关) API.of(new Object[0])是不明确的……如果我们没有在开始时添加vararg …

所以我认为他们所做的是添加足够的显式args来达到额外的堆栈大小满足vararg创建成本的程度,这可能是大约10个参数(至少基于Log4J2在将varargs添加到版本时所做的测量2 API)……但是你这样做是为了certificate未来的证据……

换句话说,我们可以欺骗所有我们没有证据需要专门实施的案例,只是落入vararg变体:

 public class API { private static final  Set internalOf(T... elements) { ... } public static final  Set of(T first) { return internalOf(first); } public static final  Set of(T first, T second) { return internalOf(first, second); } ... public static final  Set of(T t1, T t2, T t3, T t4, T t5, T... rest) { ... } } 

然后我们可以分析和查看现实世界的使用模式,如果我们看到4个argforms的重要用法和基准显示有合理的性能增益,那么在那时,在幕后,我们改变方法impl和每个人都获胜……不需要重新编译

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

所以你有了:

  1. 在一方面,这些不可变类可能被应用程序使用,其中每个位都计数(并且在分配/释放中浪费了每纳秒)。
  2. 另一方面,没有这些需求的应用程序不会受到负面影响
  3. 唯一的“消极”方面是那个API的实现者会有更多的杂乱处理,所以它影响maintanability(但在这种情况下不是一件大事)。

如果你正在实现你自己的东西我不会那么在意(但要小心varargs参数),除非你真的需要担心那些额外的位(和额外的性能etcetc)。