我可以添加流或额外的元素,如下所示:
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是一个实例方法,上面的例子会更容易阅读:
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)));
使用通用名称导入 静态方法 会导致代码变得难以阅读和维护( 命名空间污染 )。因此,使用更有意义的名称创建自己的 静态方法可能会更好。 但是,为了演示,我将坚持使用这个名称。
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);
代码现在显着缩短。但是,我同意可读性没有提高。所以我有另一个解决方案。
在很多情况下, 收集器 可用于 扩展 流的功能。底部有两个 收集器 ,这两个例子可以写成如下:
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);
您所需的语法与上述语法之间的唯一区别是,您必须将 concat(…) 替换为 collect(concat(…)) 。这两个静态方法可以实现如下(可选与静态导入结合使用):
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)); }
当然,这个解决方案有一个缺点,应该提到。 collect 是消耗流的所有元素的最终操作。最重要的是,收集器 concat 每次在链中使用时都会创建一个中间 ArrayList 。 这两种操作都会对程序的行为产生重大影响。但是,如果 可读性 比 性能 更重要,它可能仍然是一种非常有用的方法。