添加两个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.concat和Stream.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
要合并两个stream,我应该这样做:
Stream.concat(s1, s2)
不是这个:
Stream.of(s1, s2).flatMap(x -> x)
… 对?
要结合两个以上的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让你的第一个例子更具可读性。