sare
sare

Reputation: 33

How to reuse Stream after performing one operation

I want to find out Strings starting with a particular character using the same Stream twice, but the second Stream operation is throwing an exception. How can I re-use the Stream?

public static void main(String[] args) {
    Stream<String> stream = Stream.of("abc", "aef", "bcd", "bef", "crf");
    stream.filter(s -> s.startsWith("a")).forEach(System.out::println);;
    stream.filter(s -> s.startsWith("b")).forEach(System.out::println);;
}

Exception

Exception in thread "main" java.lang.IllegalStateException: stream has already been operated upon or closed
    at java.util.stream.AbstractPipeline.<init>(Unknown Source)
    at java.util.stream.ReferencePipeline.<init>(Unknown Source)
    at java.util.stream.ReferencePipeline$StatelessOp.<init>(Unknown Source)
    at java.util.stream.ReferencePipeline$2.<init>(Unknown Source)
    at java.util.stream.ReferencePipeline.filter(Unknown Source)
    at StreamExp.main(StreamExp.java:13)

Upvotes: 1

Views: 368

Answers (3)

ravthiru
ravthiru

Reputation: 9633

when you call any terminal operation the stream is closed, You could use stream supplier to construct a new stream

Supplier<Stream<String>> streamSupplier =
            () -> Stream.of("abc", "aef", "bcd", "bef", "crf");

            streamSupplier.get().filter(s -> s.startsWith("a")).forEach(System.out::println);
            streamSupplier.get().filter(s -> s.startsWith("b")).forEach(System.out::println);

Upvotes: 0

acidowl
acidowl

Reputation: 113

Use a logic OR to combine your streams into only one stream:

public static void main(String[] args) {
        Stream<String> stream = Stream.of("abc", "aef", "bcd", "bef", "crf");
        stream.filter(s -> s.startsWith("a") || s.startsWith("b")).forEach(System.out::println);
}

Upvotes: 1

Eran
Eran

Reputation: 393821

You can't perform a terminal operation such as forEach twice on the same Stream.

You have other alternatives. For example, you can produce a Map<Character,List<String>> in which the input Strings are grouped by their first character :

Map<Character,List<String>> groups = 
    Stream.of("abc", "aef", "bcd", "bef", "crf")
          .collect(Collectors.groupingBy(s->s.charAt(0)));

This will result in the following Map :

{a=[abc, aef], b=[bcd, bef], c=[crf]}

Upvotes: 2

Related Questions