默认Stream <e> stream()vs static <t> Stream <t> of(T t)

时间:2017-05-10 08:25:18

标签: functional-programming java-8 java-stream

default Stream<E> stream()被添加到Collection接口以支持Java 8中的流。public static<T> Stream<T> of(T t)Stream支持类似的功能。 ()方法解决的静态有什么不同的目的?

4 个答案:

答案 0 :(得分:6)

可以在现有集合上调用stream()接口的方法Collection。作为一种接口方法,它可以被实际的集合实现覆盖,以返回适合特定集合类型的Stream

JRE的标准集合没有抓住这个机会,因为默认实现的委托给spliterator()的策略(也是一种可覆盖的方法)适合他们的需求。但是文档甚至提到了集合应该覆盖stream()的场景:

  

如果spliterator()方法无法返回IMMUTABLECONCURRENT后期绑定的分裂器,则应覆盖此方法。

相比之下,static工厂方法Stream.of(…)是针对具有固定数量的元素而没有特定集合的情况而设计的。当你想要的只是你可以枚举的元素上的Collection时,就不需要创建一个临时的Stream

如果没有可能不同类型的集合,则不需要可覆盖的行为,因此,static工厂方法就足够了。

请注意,即使您没有可枚举的固定数量的元素,当没有可重用的集合时,还有一个针对创建单个流的任务的优化解决方案:

Stream.Builder<MyType> builder=Stream.builder();
builder.add(A);
if(condition) builder.add(B);
builder.add(C);
builder.build()./* stream operations */

答案 1 :(得分:3)

据我所知,of只是一种实用方法,可以动态创建Streams,而无需先将元素包装在集合中。

通常提供静态工厂方法of来跳过数组创建,因为var-args。例如,java-9不可变集合提供了这些方法的许多重载,如:

 Set.of()
 Set.of(E)
 Set.of(E e1, E e2)
 .... so on until 11
 Set.of(E... elem)

即使是这些方法的描述也是:

  

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

由于Stream中只有 两种方法:

 Stream.of(T t)
 Streamm.of(T ... values)

我认为可以从var-args创建Streams的小实用程序方法。

但是他们仍然提供了一种方法,用一个元素创建一个Stream(而不是让只是 var-args方法),所以对于单个元素,这已经被优化了。

答案 2 :(得分:2)

从jdk-8开始,接口可以添加静态方法/默认方法。你可以在this question中看到一些在界面上应用模式的例子。

首先,他们都在调用StreamSupport.stream来创建一个流。

// Collection.stream()
default Stream<E> stream() {
    return StreamSupport.stream(spliterator(), false);
}

// Stream.of(E)
public static<T> Stream<T> of(T t) {
    return StreamSupport.stream(new Streams.StreamBuilderImpl<>(t), false);
}
添加到Collection接口的

stream()是默认方法在接口中应用Template-Method Pattern的一个很好的例子。并且您可以看到stream方法调用方法spliterator的源代码,该方法默认在Collection接口中实现。

default Stream<E> stream() {
    return StreamSupport.stream(spliterator(), false);
}

default Spliterator<E> spliterator() {
    return Spliterators.spliterator(this, 0);
}
来自Collection

AND 类可以覆盖spliterator实现使用最高性能算法的不同算法。例如spliterator中的ArrayList

public Spliterator<E> spliterator() {
    return new ArrayListSpliterator<>(this, 0, -1, 0);
}

最后,Stream.of()方法是通过静态方法在接口中应用Factory Method的一个很好的例子。它是一个从对象实例创建流的工厂方法。

答案 3 :(得分:2)

其他答案清楚地解释了Collection.streamStream.of之间的差异,何时使用其中一种,哪些设计模式正在应用等等。@ Holger更进一步说明了示例用法我认为Stream.Builder的使用率很低。

在这里,我想通过显示Stream.ofCollection.stream方法的混合使用来补充其他答案。我希望这个例子足够清楚,表明即使Stream.ofCollection.stream都是完全不同的方法,它们也可以一起用来满足更复杂的要求。

假设您有N个列表,所有列表都包含相同类型的元素:

List<A> list1 = ...;
List<A> list2 = ...;
...
List<A> listN = ...;

并且您想要使用所有列表的元素创建一个流。

您可以创建一个新的空列表,并将所有列表的元素添加到此新列表中:

int newListSize = list1.size() + list2.size() + ... + listN.size();
List<A> newList = new ArrayList<>(newListSize);

newList.addAll(list1);
newList.addAll(list2);
...
newList.addAll(listN);

然后,你可以在这个列表上调用stream(),然后你就可以了:

Stream<A> stream = newList.stream();

但是,您将创建一个中间无意义的列表,其唯一目的是流式传输原始list1list2,...,listN列表的元素。< / p>

更好的方法是使用Stream.of

Stream<A> stream = Stream.of(list1, list2, ..., listN)
    .flatMap(Collection::stream);

这首先通过枚举每个列表来创建列表流,然后将这个列表流平面映射到所有列表的流中。通过Stream.flatMap操作的元素。因此,在对原始流进行平面映射时会调用Collection.stream