public class StreamIterable<T> implements Iterable<T> {
private final Stream<T> stream;
public StreamIterable(Stream<T> stream) {
this.stream = stream;
}
@Override
public Iterator<T> iterator() {
return new StreamIterator<>(stream);
}
}
其中
public class StreamIterator<T> implements Iterator<T> {
private final Spliterator<T> spliterator;
private boolean nextIsKnown = false;
private T next = null;
public StreamIterator(Stream<T> stream) {
this.spliterator = stream.spliterator();
}
@Override
public boolean hasNext() {
if (nextIsKnown)
return true;
return spliterator.tryAdvance(t -> {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;
}
}
测试
public class StreamIteratableTest {
@Test
public void empty() {
assertThat(new StreamIterable<>(Stream.<String>empty()), Matchers.emptyIterable());
}
@Test
public void matcher() {
Stream<String> stream = Stream.of("1", "2", "3");
assertThat(new StreamIterable<>(stream), Matchers.contains("1", "2", "3"));
}
@Test
public void torture_empty() {
StreamIterator<Object> empty = new StreamIterator<>(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<Object> twoItems = new StreamIterator<>(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<Object> twoItems = new StreamIterator<>(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());
}
}
#1 楼
两件事:我想您已经错过了本机实现。您是否有意重新发明轮子?流具有iterator()方法。
请注意,流不能反向,因此,尽管您可以一次创建一个迭代器,但不能从该流创建第二个迭代器...。换句话说,您无法循环
不止一次地考虑。考虑将您的类重做为:
public class StreamIterable<T> implements Iterable<T> {
private final Stream<T> stream;
public StreamIterable(Stream<T> stream) {
this.stream = stream;
}
@Override
public Iterator<T> iterator() {
return stream.iterator();
}
}
就这样,不需要其他代码。您仍然只能迭代一次,但是,您可以将以上内容添加到增强的for循环中:
for (String v : new StreamIterable(Files.lines(...)) {
....
}
#2 楼
为此,您不需要特殊的类。方法引用可以转换为功能接口。但是,在这种情况下,请记住,必须关闭Files::lines
返回的流以防止泄漏:try (Stream s = Files.lines(...)) {
for (String v : (Iterable<String>) s::iterator) {
...
}
}
评论
\ $ \ begingroup \ $
这里和这里都有关于此技巧的更多细节。
\ $ \ endgroup \ $
–Vadzim
15年7月29日在14:49
#3 楼
由于Iterable
是带有返回返回迭代器的方法的功能接口,因此您还可以编写:Iterable<T> it = () -> stream.iterator();
评论
\ $ \ begingroup \ $
欢迎使用代码审查!目前,您的答案仅是存根。请提供一个理由,说明为什么这比OP或其他答案提供的要好。还请记住,该问题已经存在了4年以上。
\ $ \ endgroup \ $
– AlexV
19年6月12日在11:28
\ $ \ begingroup \ $
@AlexV我不同意,我认为这是“哦,啊!我为什么没想到呢?”答案和一个非常好的。我就是这样写的。
\ $ \ endgroup \ $
–西蒙·福斯伯格
19年6月12日在14:40
\ $ \ begingroup \ $
但是,仅出于此目的,我已经编辑了此答案并对其进行了改进,使其变得更好(基本上只是在解释它的作用)。
\ $ \ endgroup \ $
–西蒙·福斯伯格
19年6月12日14:41
\ $ \ begingroup \ $
@SimonForsberg:我的Java知识有点过时了-坦率地说-这样,“哦,du!”效果超出了我。加上您的补充说明,我更喜欢这个答案。
\ $ \ endgroup \ $
– AlexV
19年6月12日在14:47
#4 楼
应当注意,Stream永远不可能真正成为Iterable,因为它不能被多次调用。但是,如果确定Stream只会被迭代一次,以便从流中创建Iterable,则只需使用表达式myStream::iterator
#5 楼
如果要使用更合适的Iterable
,请考虑使用闭包生成Stream
。它在语法上令人不快,但是该范例使您可以重复多次:public class StreamIterable<T> implements Iterable<T> {
private final Supplier<Stream<T>> streamGenerator;
public StreamIterable(Supplier<Stream<T>> streamGenerator) {
this.streamGenerator = streamGenerator;
}
@Override
public Iterator<T> iterator() {
return streamGenerator.get().iterator();
}
}
评论
\ $ \ begingroup \ $
哦,真心的悲伤-我显然是在寻找Iterable,而不是Iterator。谢谢你,另外一个精心制作的课程咬了灰尘:-)
\ $ \ endgroup \ $
–邓肯·麦格雷戈(Duncan McGregor)
2014年11月21日0:00
\ $ \ begingroup \ $
@rolfl您的代码甚至无法编译。 stream.iterator()返回Iterator <?扩展T>。 UPD:好的,请原谅,我在谈论Android的Stream API:github.com/aNNiMON/Lightweight-Stream-API。
\ $ \ endgroup \ $
–ddmytrenko
16-10-13在9:31