简体   繁体   中英

How to call multiple terminal operation on a Java stream

I know that whenever we call any terminal method on a stream , it gets closed.

If we try to call any other terminal function on a closed stream it will result in a java.lang.IllegalStateException: stream has already been operated upon or closed .

However, what if we want to reuse the same stream more than once ?

How to accomplish this?

Yes its a big NO in Java 8 streams to reuse a stream

For example for any terminal operation the stream closes when the operation is closed. But when we use the Stream in a chain, we could avoid this exception:

Normal terminal operation:

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

But instead of this, if we use:

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

Here the .get() "constructs" a new stream and NOT reuse whenever it hits this point.

Cheers!

No you can't reuse a Stream , but, if overloading heap space isn't a concern, you could save off the contents of the stream just before the terminal operation for reuse, using Stream.Builder . for example:

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

One could keep chaining streams together, adding a new Stream.Builder instance in each successive Stream .

Not the answer you were looking for, but it does avoid the overhead of doing the pipeline operations a second time. It has its own weaknesses, being bound to heap space, but it doesn't have the weakness that Holger suggested in his comment on the Supplier solution -- if it were a Random stream, it would have the same values in the second iteration.

Java 8 Streams are not really reactive, although they are quite functional. There are no multiple terminal operations. The answer mentioning Supplier while letting you write code that looks like there are multiple terminal operations, they are terminals on totally different streams that were generated independently. That is, the time complexity hasn't changed. That is equivalent to writing

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

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

The whole reason why you want multiple terminal operations is to save computation, not to make it look nice. Look at https://github.com/ReactiveX/RxJava that provides really reactive objects.

No. You cannot use a stream multiple times. What you can do is , you can collect the stream in a list and then you can call the map and forEach functions which accepts a lambda.

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

A naive example of 3 different terminal-like operations on stream elements at once:

  • displaying them,
  • counting,
  • calculating their sum

Of course this is not very elegant, but it works:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM