为现有 Stream 添加新值
Adding new value to existing Stream
有什么好的方法可以为现有 Stream
添加新值吗?我所能想象的是这样的:
public <T> Stream<T> addToStream(Stream<T> stream, T elem ) {
List<T> result = stream.collect(Collectors.toList());
result.add(elem);
return result.stream();
}
但我正在寻找更简洁的东西,我可以在 lambda 表达式中使用而不冗长。
我尝试实现PECS原理时又出现了一个问题:
public <T> Stream<? super T> addToStream(Stream<? super T> stream, T elem ) {
List<? super T> result = stream.collect(Collectors.toList()); //error
result.add(elem);
return result.stream();
}
通配符似乎不适用于 Stream.collect
,我想知道为什么。提前致谢。
怎么样
return Stream.concat(stream, Stream.of(elem));
这是假设原始 Stream 是有限的。如果不是,您可以按相反的顺序连接它们。
这个问题掩盖了一个错误的假设:流实际上包含它们的数据。他们不;流不是数据结构,它们是一种指定跨各种数据源的批量操作的方法。
有用于将两个流合并为一个的组合器,例如 Stream.concat
,还有用于从一组已知元素 (Stream.of
) 或集合 (Collection.stream
创建流的工厂).因此,如果您想生成一个新流,即您手头流的串联,以及描述新元素的新流,则可以将它们组合起来。
您的 PECS 示例中的问题是您出现了三个 ? super T
,并且您假设它们描述的是同一类型,但事实并非如此。通配符的每次出现都对应于唯一的捕获,这不是您想要的;您需要为该类型变量命名,以便编译器知道列表的类型和输入流的类型相同。 (此外,不要具体化集合;这很昂贵,如果流不是有限的,则可能不会终止。只需使用 concat。)所以答案是:你只是弄错了泛型。这是一种方法:
public<T> Stream<T> appendToStream(Stream<? extends T> stream, T element) {
return Stream.concat(stream, Stream.of(element));
}
您将自己与 PECS 混淆了,因为您正在考虑 "inserting" 进入流,而实际上您正在从中消耗。
StreamEx库有相应的#prepend()
和#append()
方法。以下是如何使用它们的示例:
StreamEx.of("second").prepend("first").append("third").forEach(System.out::println);
输出如下:
first
second
third
最好的方法是使用 flatMap,如下所示:
public <T> Stream<T> appendToStream(Stream<T> stream, T element) {
return stream.flatMap(e -> Stream.of(e, element));
}
这对原始流进行操作,因此它可以只是流上的另一个中间操作,例如:
stream.flatMap(e -> Stream.of(e, element))
.map(...)
.filter(...)
.collect(Collectors.toList());
有什么好的方法可以为现有 Stream
添加新值吗?我所能想象的是这样的:
public <T> Stream<T> addToStream(Stream<T> stream, T elem ) {
List<T> result = stream.collect(Collectors.toList());
result.add(elem);
return result.stream();
}
但我正在寻找更简洁的东西,我可以在 lambda 表达式中使用而不冗长。
我尝试实现PECS原理时又出现了一个问题:
public <T> Stream<? super T> addToStream(Stream<? super T> stream, T elem ) {
List<? super T> result = stream.collect(Collectors.toList()); //error
result.add(elem);
return result.stream();
}
通配符似乎不适用于 Stream.collect
,我想知道为什么。提前致谢。
怎么样
return Stream.concat(stream, Stream.of(elem));
这是假设原始 Stream 是有限的。如果不是,您可以按相反的顺序连接它们。
这个问题掩盖了一个错误的假设:流实际上包含它们的数据。他们不;流不是数据结构,它们是一种指定跨各种数据源的批量操作的方法。
有用于将两个流合并为一个的组合器,例如 Stream.concat
,还有用于从一组已知元素 (Stream.of
) 或集合 (Collection.stream
创建流的工厂).因此,如果您想生成一个新流,即您手头流的串联,以及描述新元素的新流,则可以将它们组合起来。
您的 PECS 示例中的问题是您出现了三个 ? super T
,并且您假设它们描述的是同一类型,但事实并非如此。通配符的每次出现都对应于唯一的捕获,这不是您想要的;您需要为该类型变量命名,以便编译器知道列表的类型和输入流的类型相同。 (此外,不要具体化集合;这很昂贵,如果流不是有限的,则可能不会终止。只需使用 concat。)所以答案是:你只是弄错了泛型。这是一种方法:
public<T> Stream<T> appendToStream(Stream<? extends T> stream, T element) {
return Stream.concat(stream, Stream.of(element));
}
您将自己与 PECS 混淆了,因为您正在考虑 "inserting" 进入流,而实际上您正在从中消耗。
StreamEx库有相应的#prepend()
和#append()
方法。以下是如何使用它们的示例:
StreamEx.of("second").prepend("first").append("third").forEach(System.out::println);
输出如下:
first
second
third
最好的方法是使用 flatMap,如下所示:
public <T> Stream<T> appendToStream(Stream<T> stream, T element) {
return stream.flatMap(e -> Stream.of(e, element));
}
这对原始流进行操作,因此它可以只是流上的另一个中间操作,例如:
stream.flatMap(e -> Stream.of(e, element))
.map(...)
.filter(...)
.collect(Collectors.toList());