为现有 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());