default Stream<E> stream()
被添加到Collection
接口以支持Java 8中的流。public static<T> Stream<T> of(T t)
类Stream
支持类似的功能。 ()方法解决的静态有什么不同的目的?
答案 0 :(得分:6)
可以在现有集合上调用stream()
接口的方法Collection
。作为一种接口方法,它可以被实际的集合实现覆盖,以返回适合特定集合类型的Stream
。
JRE的标准集合没有抓住这个机会,因为默认实现的委托给spliterator()
的策略(也是一种可覆盖的方法)适合他们的需求。但是文档甚至提到了集合应该覆盖stream()
的场景:
如果spliterator()方法无法返回
IMMUTABLE
,CONCURRENT
或后期绑定的分裂器,则应覆盖此方法。
相比之下,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.stream
和Stream.of
之间的差异,何时使用其中一种,哪些设计模式正在应用等等。@ Holger更进一步说明了示例用法我认为Stream.Builder
的使用率很低。
在这里,我想通过显示Stream.of
和Collection.stream
方法的混合使用来补充其他答案。我希望这个例子足够清楚,表明即使Stream.of
和Collection.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();
但是,您将创建一个中间无意义的列表,其唯一目的是流式传输原始list1
,list2
,...,listN
列表的元素。< / p>
更好的方法是使用Stream.of
:
Stream<A> stream = Stream.of(list1, list2, ..., listN)
.flatMap(Collection::stream);
这首先通过枚举每个列表来创建列表流,然后将这个列表流平面映射到所有列表的流中。通过Stream.flatMap
操作的元素。因此,在对原始流进行平面映射时会调用Collection.stream
。