javajava-streamiterable

Make a Stream into an Iterable?


Stream inherits an iterator() method to produce an Iterator.

But I need an Iterable rather than an Iterator.

For example, given this string:

String input = "this\n" +
        "that\n" +
        "the_other";

…I need to pass those parts of string as an Iterable to a specific library. Calling input.lines() yields a Stream. So I would be set if I could make that Stream into a Iterable of its elements.


Solution

  • As explained in Why does Stream<T> not implement Iterable<T>?, an Iterable bears the expectation to be able to provide an Iterator more than once, which a Stream can’t fulfill. So while you can create an Iterable out of a Stream for an ad-hoc use, you have to be careful about whether attempts to iterate it multiple times could exist.

    Since you said, “I need to pass those parts of string as an Iterable to a specific library”, there is no general solution as the code using the Iterable is outside your control.

    But if you are the one who creates the stream, it is possible to create a valid Iterable which will simply repeat the stream construction every time an Iterator is requested:

    Iterable<String> lines = () -> "this\nthat\nthe_other".lines().iterator();
    

    This fulfills the expectation of supporting an arbitrary number of iterations, while not consuming more resources than a single stream when being traversed only once.

    for(var s: lines) System.out.println(s);
    lines.forEach(System.out::println);
    System.out.println(String.join("\n", lines));