gpt4 book ai didi

iterator - Java 8 迭代器流到迭代器会导致对 hasNext() 的冗余调用

转载 作者:行者123 更新时间:2023-12-02 03:28:17 25 4
gpt4 key购买 nike

在以下场景中,我注意到了一些奇怪的行为:

迭代器 -> 流 -> map() -> iterator() -> 迭代

原始迭代器的 hasNext() 在已经返回 false 后被额外调用一次。

这是正常的吗?

package com.test.iterators;

import java.util.Iterator;
import java.util.Spliterators;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;

public class TestIterator {

private static int counter = 2;

public static void main(String[] args) {

class AdapterIterator implements Iterator<Integer> {
boolean active = true;

@Override
public boolean hasNext() {
System.out.println("hasNext() called");

if (!active) {
System.out.println("Ignoring duplicate call to hasNext!!!!");
return false;
}

boolean hasNext = counter >= 0;
System.out.println("actually has next:" + active);

if (!hasNext) {
active = false;
}

return hasNext;
}

@Override
public Integer next() {
System.out.println("next() called");
return counter--;
}
}

Stream<Integer> stream = StreamSupport.stream(Spliterators.spliteratorUnknownSize(new AdapterIterator(), 0), false);
stream.map(num -> num + 1).iterator().forEachRemaining(num -> {
System.out.println(num);
});
}
}

如果我删除 map() 或用类似 count() 或 collect() 之类的东西替换最终的 itearator() ,它就可以在没有冗余调用的情况下工作。

输出
hasNext() called
actually has next:true
next() called
3
hasNext() called
actually has next:true
next() called
2
hasNext() called
actually has next:true
next() called
1
hasNext() called
actually has next:true
hasNext() called
Ignoring duplicate call to hasNext!!!!

最佳答案

是的,这是正常的。冗余调用发生在 StreamSpliterators.AbstractWrappingSpliterator.fillBuffer() ,从 hasNext() 调用stream.map(num -> num + 1).iterator() 返回的迭代器的方法.来自 JDK 8 源代码:

/**
* If the buffer is empty, push elements into the sink chain until
* the source is empty or cancellation is requested.
* @return whether there are elements to consume from the buffer
*/
private boolean fillBuffer() {
while (buffer.count() == 0) {
if (bufferSink.cancellationRequested() || !pusher.getAsBoolean()) {
if (finished)
return false;
else {
bufferSink.end(); // might trigger more elements
finished = true;
}
}
}
return true;
}

调用 pusher.getAsBoolean()电话 hasNext()上原 AdapterIterator实例。如果为真,它将下一个元素添加到 bufferSink并返回真,否则返回假。当原始迭代器用完项目并返回 false 时,此方法调用 bufferSink.end()并重试填充缓冲区,这导致了多余的 hasNext()称呼。

在这种情况下, bufferSink.end()没有效果,第二次尝试填充缓冲区是不必要的,但正如源评论所解释的那样,它在另一种情况下“可能会触发更多元素”。这只是一个深埋在 Java 8 流复杂内部工作中的实现细节。

关于iterator - Java 8 迭代器流到迭代器会导致对 hasNext() 的冗余调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29037100/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com