添加两个Java 8stream或一个额外的元素到一个stream

我可以添加stream或额外的元素,如下所示:

Stream stream = Stream.concat(stream1, Stream.concat(stream2, Stream.of(element)); 

我可以随时添加新的东西,像这样:

 Stream stream = Stream.concat( Stream.concat( stream1.filter(x -> x!=0), stream2) .filter(x -> x!=1), Stream.of(element)) .filter(x -> x!=2); 

但这很丑,因为concat是静态的。 如果concat是一个实例方法,上面的例子会更容易阅读:

  Stream stream = stream1.concat(stream2).concat(element); 

  Stream stream = stream1 .filter(x -> x!=0) .concat(stream2) .filter(x -> x!=1) .concat(element) .filter(x -> x!=2); 

我的问题是:

1) concat是静态的吗? 还是有一些等价的实例方法,我失踪了?

2)无论如何,有没有更好的方法来做到这一点?

如果为Stream.concatStream.of添加静态导入 ,则可以按如下方式编写第一个示例:

 Stream<Foo> stream = concat(stream1, concat(stream2, of(element))); 

导入具有不同用途名称的静态方法是个不错的主意。 所以最好用更有意义的名字来创build你自己的静态方法 。 然而,为了演示,我会坚持这个名字。

 public static <T> Stream<T> concat(Stream<? extends T> lhs, Stream<? extends T> rhs) { return Stream.concat(lhs, rhs); } public static <T> Stream<T> concat(Stream<? extends T> lhs, T rhs) { return Stream.concat(lhs, Stream.of(rhs)); } 

通过这两个静态方法(可选地结合静态导入),这两个例子可以写成如下:

 Stream<Foo> stream = concat(stream1, concat(stream2, element)); Stream<Foo> stream = concat( concat(stream1.filter(x -> x!=0), stream2).filter(x -> x!=1), element) .filter(x -> x!=2); 

代码现在显着缩短。 但是,我同意可读性没有改善。 所以我有另一个解决scheme。


在很多情况下, 收集器可以用来扩展stream的function。 两个collections家在底部,这两个例子可以写成如下:

 Stream<Foo> stream = stream1.collect(concat(stream2)).collect(concat(element)); Stream<Foo> stream = stream1 .filter(x -> x!=0) .collect(concat(stream2)) .filter(x -> x!=1) .collect(concat(element)) .filter(x -> x!=2); 

你想要的语法和上面的语法唯一的区别是,你必须用collect(concat(…))replaceconcat(… 。 这两个静态方法可以实现如下(可选地与静态导入结合使用):

 private static <T,A,R,S> Collector<T,?,S> combine(Collector<T,A,R> collector, Function<? super R, ? extends S> function) { return Collector.of( collector.supplier(), collector.accumulator(), collector.combiner(), collector.finisher().andThen(function)); } public static <T> Collector<T,?,Stream<T>> concat(Stream<? extends T> other) { return combine(Collectors.toList(), list -> Stream.concat(list.stream(), other)); } public static <T> Collector<T,?,Stream<T>> concat(T element) { return concat(Stream.of(element)); } 

当然,这个解决scheme有一个缺点,应该提到。 collect是消耗stream的所有元素的最终操作。 最重要的是,收集器concat每次在链中使用时创build一个中间ArrayList 。 这两种操作都会对程序的行为产生重大影响。 但是,如果可读性性能更重要,它可能仍然是一个非常有用的方法。

不幸的是,这个答案可能没有什么帮助,但是我对Java Lambda邮件列表进行了取证分析,看看能否find这个devise的原因。 这是我发现的。

开始时有一个Stream.concat(Stream)的实例方法,

在邮件列表中,我可以清楚地看到方法最初是作为一个实例方法实现的,正如你可以在Paul Sandoz的这个线程中读到的有关concat操作的方法。

在这里,他们讨论可能会产生的问题,这些问题可能是无限的,在这种情况下串联意味着什么,但我不认为这是修改的原因。

您可以在这个其他线程中看到,JDK 8的一些早期用户在使用空参数时,对concat实例方法的行为提出质疑。

然而, 另一个线程揭示了concat方法的devise正在讨论之中。

重构为Streams.concat(stream,stream)

但没有任何解释,突然间,方法被改为静态方法,就像你在这个线程中看到的有关组合stream的东西 。 这也许是唯一一条对这个改变略微有点了解的邮件,但是我不清楚重构的原因。 但是我们可以看到他们做了一个提交 ,他们build议将concat方法从Stream移动到辅助类Streams

重构为Stream.concat(stream,stream)

后来, 它又从Streams移到Stream ,但是再一次没有解释。

因此,底线,devise的原因并不完全清楚,我找不到一个好的解释。 我想你仍然可以在邮件列表中提问。

stream连接的一些select

迈克尔·希克森另一个线程讨论/询问其他方式来组合/ concatstream

  1. 要合并两个stream,我应该这样做:

     Stream.concat(s1, s2) 

    不是这个:

     Stream.of(s1, s2).flatMap(x -> x) 

    … 对?

  2. 要结合两个以上的stream,我应该这样做:

     Stream.of(s1, s2, s3, ...).flatMap(x -> x) 

    不是这个:

     Stream.of(s1, s2, s3, ...).reduce(Stream.empty(), Stream::concat) 

    … 对?

我的StreamEx库扩展了Stream API的function。 特别是它提供了像append和prepend这样的方法来解决这个问题(在内部使用concat )。 这些方法可以接受另一个stream或集合或可变参数数组。 使用我的库,你的问题可以通过这种方式来解决(请注意,对于非原始stream, x != 0看起来很奇怪):

 Stream<Integer> stream = StreamEx.of(stream1) .filter(x -> !x.equals(0)) .append(stream2) .filter(x -> !x.equals(1)) .append(element) .filter(x -> !x.equals(2)); 

顺便说一下,你的filter操作也有一个快捷方式:

 Stream<Integer> stream = StreamEx.of(stream1).without(0) .append(stream2).without(1) .append(element).without(2); 

做就是了:

 Stream.of(stream1, stream2, Stream.of(element)).flatMap(identity()); 

其中identity()Function.identity()的静态导入。

将多个stream连接成一个stream与平坦化一个stream相同。

然而,不幸的是,出于某种原因,在Stream上没有flatten()方法,所以你必须使用flatMap()和identity函数。

如果你不介意使用第三方库, cyclops-react有一个扩展的Streamtypes,可以通过append / prepend操作符来做到这一点。

单个值,数组,迭代,stream或反应stream发布者可作为实例方法附加和前置。

 Stream stream = ReactiveSeq.of(1,2) .filter(x -> x!=0) .append(ReactiveSeq.of(3,4)) .filter(x -> x!=1) .append(5) .filter(x -> x!=2); 

[披露我是独眼巨人反应的主要开发者]

你可以使用番石榴的溪stream 。 concat(Stream … streams)方法,这将与静态导入非常短:

 Stream stream = concat(stream1, stream2, of(element)); 

如何编写自己的concat方法?

 public static Stream<T> concat(Stream<? extends T> a, Stream<? extends T> b, Stream<? extends T> args) { Stream<T> concatenated = Stream.concat(a, b); for (Stream<T> stream : args) { concatenated = Stream.concat(concatenated, stream); } return concatenated; } 

这至less让你的第一个例子更具可读性。