如何在Java流上调用多个终端操作

时间:2017-03-02 10:08:30

标签: java java-8 java-stream reusability

我知道每当我们在 <InputElement mask="+7 (999) 999-99-99" alwaysShowMask={true} {...this.props} maskChar=" " /> 上拨打任何terminal method时,它就会被关闭。

如果我们尝试在封闭流上调用任何其他终端函数,则会产生stream

但是,如果我们想要多次重复使用相同的流,该怎么办?

如何做到这一点?

5 个答案:

答案 0 :(得分:2)

是的,它是Java 8流中重用流的重要原因

例如,对于任何终端操作,当操作关闭时,流将关闭。但是当我们在链中使用Stream时,我们可以避免这种异常:

正常终端操作:

Stream<String> stream =
    Stream.of("d2", "a2", "b1", "b3", "c")
        .filter(s -> s.startsWith("a"));

stream.anyMatch(s -> true);    // ok
stream.noneMatch(s -> true);   // exception

但如果我们使用:

而不是这个
Supplier<Stream<String>> streamSupplier =
    () -> Stream.of("d2", "a2", "b1", "b3", "c")
            .filter(s -> s.startsWith("a"));

streamSupplier.get().anyMatch(s -> true);   // ok
streamSupplier.get().noneMatch(s -> true);  // ok

这里.get()“构造了一个新的流,并且只要它到达这一点就不会重用。

干杯!

答案 1 :(得分:0)

不,你不能重用Stream,但是,如果不考虑重载堆空间,你可以在终端操作之前保存流的内容以便重用,使用{ {1}}。例如:

Stream.Builder

可以将流链接在一起,在每个连续的Stream<OriginalType> myStream = ... Stream.Builder<SomeOtherType> copy = Stream.builder(); List<SomeOtherType> aList = myStream .filter(...) .map(...) // eventually maps to SomeOtherType .peek(copy) // pour values into a new Stream .collect(Collectors.toList()); Set<SomeOtherType> aSet = copy.build() .collect(Collectors.toSet()); 中添加一个新的Stream.Builder实例。

不是您正在寻找的答案,但它确实避免了第二次进行管道操作的开销。它有自己的弱点,受限于堆空间,但它并没有Holger在他对Stream解决方案的评论中提出的弱点 - 如果它是Supplier流,它在第二次迭代中具有相同的值。

答案 2 :(得分:0)

尽管Java 8 Streams具有相当的功能,但它们并不是真正的反应性。没有多个终端操作。提及供应商的答案,使您可以编写看起来像有多个终端操作的代码,它们是完全独立生成的不同流上的终端。也就是说,时间复杂度没有改变。相当于写

Stream getStream() {
   return Stream.of(....);
}

static void main() {
   Values values1 = getStream().collect();
   Values values2 = getStream().collect();
}

要进行多个终端操作的全部原因是为了节省计算量,而不是使其看起来不错。看一下https://github.com/ReactiveX/RxJava,它提供了真正的反应对象。

答案 3 :(得分:0)

不。您不能多次使用流。 您可以做的是,可以将流收集在列表中,然后可以调用map和forEach函数,该函数接受lambda。

List<String> list =
    Stream.of("test")
        .filter(s -> s.startsWith("a"))
        .collect(Collectors.toList());
list.forEach(item -> item);
list.map(item -> item);

答案 4 :(得分:0)

一次对流元素进行 3 种不同的类似终端的操作的简单示例:

  • 显示它们,
  • 计数,
  • 计算它们的总和

当然这不是很优雅,但确实有效:

    List<Integer> famousNumbers = List.of(0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55);
    Stream<Integer> numbersStream = famousNumbers.stream();
    Stream<Integer> numbersGreater5Stream = numbersStream.filter(x -> x > 5);

    var ref = new Object() {
        int counter = 0;
        int sum = 0;
    };

    numbersGreater5Stream.forEach(x -> {
        System.out.print(x + " ");
        ref.counter++;
        ref.sum += x;
    });

    System.out.println("\n" + ref.counter + " " + ref.sum);