在Java 9中重载的方便工厂方法的重点是什么?

are*_*res 25 java collections variadic-functions java-9

Java 9附带了用于创建不可变列表的便捷工厂方法.最后,列表创建非常简单:

List<String> list = List.of("foo", "bar");
Run Code Online (Sandbox Code Playgroud)

但是这个方法有12个重载版本,11个有0到10个元素,另一个有var args.

static <E> List<E>  of(E... elements)
Run Code Online (Sandbox Code Playgroud)

同样是与案件SetMap.

由于存在var args方法,有多少11种方法有什么意义呢?

我认为var-args创建一个数组,所以其他11个方法可以跳过创建一个额外的对象,在大多数情况下会有0-10个元素.还有其他原因吗?

Nam*_*man 26

来自JEP文档本身 -

描述 -

这些将包括varargs重载,因此对集合大小没有固定限制.但是,如此创建的集合实例可以针对较小的尺寸进行调整.将提供最多十个元素的特殊情况API(固定参数重载).虽然这会在API中引入一些混乱,但它避免了varargs调用引起的数组分配,初始化和垃圾收集开销.值得注意的是,无论是否调用fixed-arg或varargs重载,调用站点的源代码都是相同的.


编辑 - 为了增加动力,正如@CKing在评论中已提到的那样:

非目标 -

支持具有任意数量元素的高性能,可伸缩集合并非目标.重点是小集合.

动机 -

创建一个小的,不可修改的集合(比如一组)包括构造它,将它存储在局部变量中,并在其上多次调用add(),然后将其包装起来.

Set<String> set = Collections.unmodifiableSet(new HashSet<>(Arrays.asList("a", "b", "c")));
Run Code Online (Sandbox Code Playgroud)

通过组合流工厂方法和收集器,Java 8 Stream API可用于构建小型集合.

// Java 8
Set<String> set1 = Collections.unmodifiableSet(Stream.of("a", "b", "c").collect(Collectors.toSet()));
Run Code Online (Sandbox Code Playgroud)

通过提供用于创建小型集合实例的库API,与更改语言相比,成本和风险显着降低,可以获得集合文字的大部分好处.例如,创建小型Set实例的代码可能如下所示:

// Java 9 
Set set2 = Set.of("a", "b", "c");
Run Code Online (Sandbox Code Playgroud)

  • @CKing是的,这是一个微优化.JDK库的性能标准比大多数应用程序严格得多.这些API在JDK本身中使用,它们会影响启动时间,因此即使是显而易见的微小优化也是值得的. (22认同)
  • @Eugene是的,它隐藏在实现中,它可以兼容地改变.它还没有完全优化. (6认同)
  • 在您可以使用 Java 等高级语言使用大量硬件的时代,这难道不是一种微优化吗?我真希望有另一个原因,但想不出一个 (3认同)
  • @StuartMarks然后他们所有人(除了两个参数方法)委托给他们:`@SafeVarargs @SuppressWarnings("unchecked")SetN(E ... input){` (2认同)
  • @CKing API适用于一般用途.但是我们希望能够在JDK中使用它们而不牺牲性能.关于新API的一般用法,源代码通常不需要知道或关心它是否正在调用fixed-arg或varargs方法.如果你有`Set.of(a1,a2,... a10)`并且你添加另一个arg,它最终会从固定调用切换到varargs调用,但是否则它的行为完全相同.所以,继续使用新的API. (2认同)

Mur*_*nik 10

如您所料,这是性能增强.Vararg方法在"引擎盖下"创建一个数组,并且具有直接采用1-10个参数的方法避免了这种冗余的数组创建.

  • @DanNeely&@ares:具有讽刺意味的是,`hot loops`场景肯定[被认为是不相关的](http://mail.openjdk.java.net/pipermail/core-libs-dev/2015-November/036439.html)优化. (6认同)
  • 在您可以使用 Java 等高级语言使用大量硬件的时代,这难道不是一种微优化吗?我真希望有另一个原因,但想不出一个。 (2认同)
  • @CKing语言/库设计者需要考虑代码的性能,而不仅仅是在不经常运行的代码中; 但是当有人在计算密集型应用程序的热循环中使用它时会发生什么.在那些情况下,否则可能被视为"毫无意义的微观优化"的事情确实会对性能产生重大影响. (2认同)
  • @DanNeely这个论点在这种情况下有效吗?创建10个元素的数组有多贵? (2认同)

jub*_*0bs 6

您可能会发现Josh Bloch的Effective Java(第2版)第42项的以下段落具有启发性:

每次调用varargs方法都会导致数组分配和初始化.如果你根据经验确定你不能承担这笔费用,但你需要varargs的灵活性,有一种模式可以让你吃蛋糕并吃掉它.假设您已确定95%的方法调用具有三个或更少的参数.然后声明方法的五个重载,一个用零到三个普通参数,以及一个varargs方法,当参数个数超过三个时使用[...]

  • 最重要的两个词要注意:*根据经验确定*。微优化绝对需要经验证明。 (2认同)