为什么要在 Java Stream 接口中重载可变参数方法 of()?

Why overload the varargs method of() in Java Stream interface?

Stream 接口有两个重载方法 of()。其中一个是可变元数方法,而另一个采用单个参数。

与将一个参数传递给可变参数方法相比,单参数方法是一种性能优化吗?如果是这样,它如何提高性能?可以对 empty() 方法提出相同的问题,这似乎是围绕可变元数 of().

的语法糖

我发现这些方法的实现方式不同,区别显然在于 Spliterator 的实例化方式;但这对 Stream API 有什么好处?

是的,这是一种优化,可以避免创建仅包含单个元素的数组的开销,如果您使用可变参数版本,就会得到这种开销。

The same questions could be asked of the empty() method, which would seem to be syntax sugar around the variable-arity of()

您正在查看哪个实施版本?当我查看实现时,我没有看到这一点。

空流和单元素流是非常常见的用例,尤其是当您使用 .flatMap() 时。例如,Optional.stream() 在 Java-9 中是 implemented

public Stream<T> stream() {
    if (!isPresent()) {
        return Stream.empty();
    } else {
        return Stream.of(value);
    }
}

所以给定 Optional 流,您可以通过这种方式将它们解包到平面流中:

streamOfOptionals.flatMap(Optional::stream);

在这里你创建了大量的空流和单元素流,所以优化这种情况看起来非常合理。特别是,Stream.empty()Stream.of() 不同,它不会创建空数组,也不会创建拆分器(它会重用相同的拆分器实例)。 Stream.of(T)也在StreamBuilderImpl内部进行了特别优化,所以没有为单个元素分配数组。

我偶然发现了一个官方资源,它证实了之前对这个问题的回答:JEP 269: Convenience Factory Methods for Collections。该提案的描述是,

Provide static factory methods on the List, Set, and Map interfaces for creating unmodifiable instances of those collections.

These will include varargs overloads, so that there is no fixed limit on the collection size... Special-case APIs (fixed-argument overloads) for up to ten of elements will be provided. While this introduces some clutter in the API, it avoids array allocation, initialization, and garbage collection overhead that is incurred by varargs calls.

所以性能优化很简单,就是避免可变参数方法的数组。