java - concat - 将两个Java 8流或一个额外的元素添加到流中

97 5

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

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 是 static 。 如果 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 是 static的原因? 还是有一些等价的实例方法我丢失了?

2 ) 在任何情况下,都是否有更好的方法进行这里操作?

时间: 原作者:

105 3

如果你添加 static 导入 Stream.concat 和 Stream.of,第一个示例可以如下所示:

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

导入具有通用名称的static 方法可能会导致难以读取和维护( 命名空间污染 )的代码。 因此,最好创建你自己的static 方法,以更有意义的名称命名。 不过,为了演示,我将坚持这个名称。

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));
}

使用这两个 static 方法( 可以选择与 static 导入组合),可以按如下方式编写两个示例:

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 collect collect 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在链中每次使用时创建一个中间的 。 这两个操作都会对程序的行为产生重大影响。 然而,如果可读性比性能更重要,它仍然是一种非常有用的方法。

原作者:
97 4

不幸的是,这个答案可能很少或没有任何帮助,但我对Java Lambda邮件列表进行了取证分析,看看我是否能找到这种设计的原因。 这是我发现的办法:

开始的有一个实例方法用于 Stream.concat(Stream)

在邮件列表中,我可以清楚地看到该方法最初是作为实例方法实现的,正如您可以阅读Paul Sandoz在此主题中关于concat操作的内容。

在其中,他们讨论了流可能无限的情况以及在这些情况下串联意味着什么的问题,但我不认为这是修改的原因。

您在另一个帖子中看到JDK 8的一些早期用户在使用null参数时询问了concat实例方法的行为。

但是,这个它的他线程,显示,该方法的设计正在讨论中。

向 Streams.concat(Stream,Stream) 重构了

但是,没有任何解释,突然,这个方法变成了 static 方法,就像你在中看到的,这个线程关于组合流。 这可能是唯一能够揭示这一变化的邮件帖子,但对于我来说,确定重构的原因尚不清楚。 但是我们可以看到他们提交他们建议将 concat 方法移到 Stream 中,并进入 helper 类 Streams

向 Stream.concat(Stream,Stream) 重构了

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

所以,底线,设计的原因对我来说并不完全清楚,我找不到一个好的解释。 我想你还是可以在邮件列表中提问。

为流连接 Alternatives

Michael Hixson的其他线程讨论/询问关于合并/concat流的其他方法

要合并两个流,我应该这样做:

Stream.concat(s1, s2)

不是这样的:

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

。正确?

要合并两个上的流,我应该这样做:

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

不是这样的:

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

。正确?

...