StreamIterable - create an iterable from a Java 8 Stream This seems like an easy thing to mess up, so I'd be grateful if you could think of any edge-cases that I've missed.

public class StreamIterable&lt;T&gt; implements Iterable&lt;T&gt; {

  private final Stream&lt;T&gt; stream;

  public StreamIterable(Stream&lt;T&gt; stream) {
    this.stream = stream;
  }

  @Override
  public Iterator&lt;T&gt; iterator() {
    return new StreamIterator&lt;&gt;(stream);
  }
}


where 

public class StreamIterator&lt;T&gt; implements Iterator&lt;T&gt; {
  private final Spliterator&lt;T&gt; spliterator;

  private boolean nextIsKnown = false;
  private T next = null;

  public StreamIterator(Stream&lt;T&gt; stream) {
    this.spliterator = stream.spliterator();
  }

  @Override
  public boolean hasNext() {
    if (nextIsKnown)
        return true;
    return spliterator.tryAdvance(t -&gt; {next = t; nextIsKnown = true;});
  }

  @Override
  public T next() {
    if (nextIsKnown) {
        return resetAndReturnNext();
    }
    if (!hasNext())
        throw new NoSuchElementException();
    return resetAndReturnNext();
  }

  private T resetAndReturnNext() {
    T result = next;
    nextIsKnown = false;
    next = null;
    return result;
  }
}


Tests

public class StreamIteratableTest {

    @Test
    public void empty() {
        assertThat(new StreamIterable&lt;&gt;(Stream.&lt;String&gt;empty()), Matchers.emptyIterable());
    }


    @Test
    public void matcher() {
        Stream&lt;String&gt; stream = Stream.of("1", "2", "3");
        assertThat(new StreamIterable&lt;&gt;(stream), Matchers.contains("1", "2", "3"));
    }

    @Test
    public void torture_empty() {
        StreamIterator&lt;Object&gt; empty = new StreamIterator&lt;&gt;(Stream.empty());

        assertFalse(empty.hasNext());
        try {
            empty.next();
            fail();
        } catch (NoSuchElementException expected) {
        }

        assertFalse(empty.hasNext());
        assertFalse(empty.hasNext());
        try {
            empty.next();
            fail();
        } catch (NoSuchElementException expected) {
        }
        try {
            empty.next();
            fail();
        } catch (NoSuchElementException expected) {
        }
    }

    @Test
    public void dont_call_hasNext() {
        StreamIterator&lt;Object&gt; twoItems = new StreamIterator&lt;&gt;(Stream.of("1", "2"));

        assertEquals("1", twoItems.next());
        assertEquals("2", twoItems.next());
        try {
            twoItems.next();
            fail();
        } catch (NoSuchElementException expected) {
        }
    }

    @Test
    public void repeat_call_hasNext() {
        StreamIterator&lt;Object&gt; twoItems = new StreamIterator&lt;&gt;(Stream.of("1", "2"));

        assertTrue(twoItems.hasNext());
        assertTrue(twoItems.hasNext());
        assertEquals("1", twoItems.next());
        assertTrue(twoItems.hasNext());
        assertEquals("2", twoItems.next());
        assertFalse(twoItems.hasNext());
        assertFalse(twoItems.hasNext());
    }   
}
Two things:


I think you have missed the native implementation. Are you intentionally re-inventing the wheel? Streams have an iterator() method.
Note that streams cannot be reversed, so, while you can create an iterator once, from the stream, you cannot create a second iterator.... In other words, you cannot loop more than once through your iterable.


Consider reworking your class as:

public class StreamIterable&lt;T&gt; implements Iterable&lt;T&gt; {

  private final Stream&lt;T&gt; stream;

  public StreamIterable(Stream&lt;T&gt; stream) {
    this.stream = stream;
  }

  @Override
  public Iterator&lt;T&gt; iterator() {
    return stream.iterator();
  }
}


That's it, no additional code needed. You can still only iterate it once, but, you can add the above to an enhanced-for loop:

for (String v : new StreamIterable(Files.lines(...)) {
    ....
}