为现有Stream添加新值

时间:2015-02-28 19:21:36

标签: java java-8 wildcard

是否有一种向现有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一起使用,我想知道原因。提前谢谢。

5 个答案:

答案 0 :(得分:82)

这个问题掩盖了一个错误的假设:流实际上包含他们的数据。他们不;流不是数据结构,它们是指定跨各种数据源的批量操作的手段。

有两个组合在一起的组合器,例如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混淆了,因为你正在考虑&#34;插入&#34;进入流中,实际上你正在消费它。

答案 1 :(得分:25)

怎么样

return Stream.concat(stream, Stream.of(elem));

这假设原始流是有限的。如果不是,你可以按相反的顺序连接它们。

答案 2 :(得分:1)

StreamEx库具有适当的#prepend()#append()方法。以下是如何使用它们的示例:

StreamEx.of("second").prepend("first").append("third").forEach(System.out::println);

输出如下:

first
second
third

答案 3 :(得分:0)

  1. 将流转换为列表
  2. 添加新项
  3. 转换回流

答案 4 :(得分:-1)

最好的方法是如下使用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());