我的理解是,它需要检查hasNext,然后如果它是true,则调用下一个方法来获取迭代器中的元素。
问题:
它在检索元素后调用hasNext,在我的示例中,使用next检索最后一个元素并检查hasNext,然后返回false并结束循环。因此,我处理N-1元素而不是N元素。
或者,我使用了下面的代码。
Stream.generate(() -> j)
.takeWhile(SlidingWindow::hasNextTimePeriod)
.map(slider -> slider.next())复制代码:
@Slf4j
class Java9StreamTest {
@Test
void testStream() {
final SlidingWindows slidingWindows = new SlidingWindows();
Stream.iterate(slidingWindows.next(), j -> slidingWindows.hasNext(), j -> slidingWindows.next())
.forEach(value -> log.info("{}", value));
}
}
class SlidingWindows {
private final List<String> list = List.of("A", "B", "C");
private int count = 0;
public boolean hasNext() {
return count < list.size();
}
public String next() {
final String result = list.get(count);
count = count + 1;
return result;
}
}产出:
20:20:03.485 [main] INFO mohan.stream.Java9StreamTest - A
20:20:03.489 [main] INFO mohan.stream.Java9StreamTest - B缺少最后一个元素C
它的工作方式类似于for循环,在Java中使用hasNext和next是有误导性的。
在流中,什么等同于下面的代码?
while(slidingWindows.hasNext()) {
final String next = slidingWindows.next();
log.info("{}", next);
}发布于 2022-06-02 19:32:13
根据文档,Stream.iterate()利用引擎盖下的for循环:
Stream.iterate应该生成与对应的for-循环相同的元素序列:
对于(T index=seed;hasNext.test(索引);index =next.apply(索引)){.},如果hasNext谓词不保留种子值,则结果序列可能为空。否则,第一个元素将是提供的种子值,下一个元素(如果存在)将是将next函数应用于种子值的结果,等等,直到hasNext谓词指示流应该终止。
因此,基本上,iterate()种子的第一个参数对应于for循环的初始化表达式,第二个参数(谓词)充当终止表达式,第三个参数(一元操作符)扮演增量表达式()的角色。
示例
让我们来看看下面的几个例子:
Iterator<String> iter = List.of("A", "B", "C").iterator();
Stream.iterate(iter.next(), str -> iter.hasNext(), str -> iter.next())
.forEach(System.out::println);这与以下几点相同:
Stream.generate(() -> "dummy")
.map(str -> iter.next()) // requesting the element
.peek(str -> System.out.println(str + " <- invoking next()"))
.takeWhile(str -> {
boolean result = iter.hasNext(); // checking whether the next element exists
System.out.println(result + " <- invoking hasNext()");
return result;
})
.forEach(str -> System.out.println(str + " <- has reached the terminal operation\n"));第二个流的输出:
A <- invoking next()
true <- invoking hasNext()
A <- has reached the terminal operation
B <- invoking next()
true <- invoking hasNext()
B <- has reached the terminal operation
C <- invoking next()
false <- invoking hasNext()让我们探讨所有的行动:
iter.next()将检索第一个元素A (在第二个流中,它将由map操作完成)。然后将触发谓词iter.next()。然后,
B,谓词将起作用。然后,
C,谓词iter.next()将返回false,因为源已经耗尽。结论:在这两种情况下,在执行谓词之前从源抓取最后一个元素C,并且由于源已经为空,谓词将被求值为false,该元素将被抛出。
怎么修呢?
要使它成功地从源检索所有元素,您需要交换map和takeWhile,即首先检查是否有下一个元素,然后才请求下一个元素
Iterator<String> iter = List.of("A", "B", "C").iterator();
Stream.generate(() -> "dummy")
.takeWhile(str -> iter.hasNext())
.map(str -> iter.next())
.forEach(System.out::println);输出:
A
B
C此修复只适用于组合takeWhile + map,但不能更改iterate()的行为。
正如@Slow在注释中提到的那样,如果您使SlidingWindows类实现了Iterator接口,那么您可以使用StreamSupport实用程序类,它将负责将所有元素转换成流,如这里所述:Why does Iterable not provide stream() and parallelStream() methods?
注意,它还需要将迭代器转换为Spliterator的实例,这可以通过使用Spliterators实用程序类的静态方法spliteratorUnknownSize()来完成。
StreamSupport.stream(
Spliterators.spliteratorUnknownSize(iter, Spliterator.ORDERED),
false) // a flag that denotes whether the stream should be parallel
.forEach(System.out::println);https://stackoverflow.com/questions/72480687
复制相似问题