在Spliterator的.tryAdance()实现中,是否存在使用.accept()多个元素的危险? [英] Is there any danger in making the action .accept() more than one element in an implementation of Spliterator's .tryAdance()?

查看:159
本文介绍了在Spliterator的.tryAdance()实现中,是否存在使用.accept()多个元素的危险?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

Spliterator 的javadoc提到:

The javadoc of Spliterator mentions that:


Spliterator可以遍历元素单独(tryAdvance())或顺序(forEachRemaining())。

A Spliterator may traverse elements individually (tryAdvance()) or sequentially in bulk (forEachRemaining()).

然后我们转到 javadoc tryAdvance() 那个:

Then we go to the javadoc of tryAdvance() which says that:


如果剩下的元素存在,则对它执行给定的操作,返回true;否则返回false。

If a remaining element exists, performs the given action on it, returning true; else returns false.

也许我在某处误读,但对我来说似乎只要有一个元素,或更多,剩下的, Consumer 作为参数应该只返回每个 .accept()一个参数 true ,如果说,我有两个参数可以立即使用,那么我不能:

Maybe I am misreading somewhere, but to me it seems that provided there is one element, or more, remaining, the Consumer as an argument should only every .accept() one argument before returning true, and that if, say, I have two arguments immediately available, then I cannot:

action.accept(arg1);
action.accept(arg2);
return true;

这个项目,我已经重写了广泛的第一个分裂器,现在它读取:

In this project, I have rewritten the breadth first spliterator so that it now reads:

// deque is a Deque<Iterator<T>>

@Override
public boolean tryAdvance(final Consumer<? super T> action)
{
    Iterator<T> iterator;
    T element;

    while (!deque.isEmpty()) {
        iterator = deque.removeFirst();
        while (iterator.hasNext()) {
            element = iterator.next();
            deque.add(fn.apply(element));
            action.accept(element);
        }
    }
    return false;
}

简而言之,我做了行动接受所有参数,然后返回false ...并且测试虽然很简单,但仍然成功(链接)。

In short, I make the action accept all arguments, and then return false... and the test, albeit quite simple, still succeeds (link).

注意 .trySplit()始终返回 null ;并且分裂器具有特征 DISTINCT ORDERED NONNULL

Note that .trySplit() always returns null; and the spliterator has chacacteristics DISTINCT, ORDERED and NONNULL.

那么,是否有一个流使用,由于上面的方法一次性消耗所有元素,上面的代码将无法工作?

So, is there a stream usage in which the code above will not work due to the method above consuming all elements at once?

推荐答案

你假设 tryAdvance()应该只消耗一个元素是对的。但是,这并不意味着您会立即注意到违反合同的行为。当您使用 .collect(Collectors.toList())等操作进行测试时,甚至不太可能发现这样的违规行为,因为大多数消耗所有元素的操作都将在spliterator上调用<$ h $ =https://docs.oracle.com/javase/8/docs/api/java/util/Spliterator上的 forEachRemaining()。 html#forEachRemaining-java.util.function.Consumer-rel =nofollow noreferrer> 默认实施记录为:

Your assumption that tryAdvance() should only consume one element is right. This, however, does not imply that you will notice violations of the contract immediately. When you test using operations like .collect(Collectors.toList()) it’s even unlikely to spot such a violation as most operations consuming all elements will invoke forEachRemaining() on the spliterator whose default implementation is documented as:


默认实现重复调用tryAdvance(java.util.function.Consumer),直到它返回false。

The default implementation repeatedly invokes tryAdvance(java.util.function.Consumer) until it returns false.

显然,对于那个方法没什么区别。

Obviously, for that method it makes no difference.

Stream框架将调用 tryAdvance()执行延迟操作时。因此,当您使用 .peek(System.out :: println).findFirst()时,您可能会注意到 tryAdvance()实现推送多个值。仍然,给出了当前的实现,结果是正确的第一个元素。显然,实现提供的消费者在遇到值后忽略后续值。

The Stream framework will invoke tryAdvance() when performing lazy operations. So when you use .peek(System.out::println).findFirst() you may notice a difference when your tryAdvance() implementation pushes more than one value. Still, given the current implementation, the result is the correct first element. Apparently, the implementation-provided consumer ignores subsequent values after encountering a value.

这可能与其他实现细节相关联,如为什么在flatflow()之后的filter()在Java流中不完全是懒惰的?。如果流实现本身在某些情况下推送的值超过了必要的值,那么同一实现中的接收端必须准备好处理这种情况。

This might be connected to other implementation details like the one discussed in "Why filter() after flatMap() is ‘not completely’ lazy in Java streams?". If the stream implementation itself pushes more values than necessary under certain circumstances, the receiving end in the same implementation must be prepared to handle that case.

但必须强调的是这是一个特定Stream API实现的行为。不同的实现或下一个Java版本可能依赖于 tryAdvance 的正确实现。此外,除了Streams之外,可能还有 Spliterator 的用例。

But it must be emphasized that this is the behavior of one particular Stream API implementation. A different implementation or the next Java version might rely on a correct implementation of tryAdvance. Further, there might be use cases for Spliterators other than Streams.

好吧,我终于找到了一个与 Spliterator 打破的操作示例:

Well, I finally found an example of an operation that breaks with your Spliterator:

for(Iterator<?> it=Spliterators.iterator(spliterator); it.hasNext();) {
    System.out.println(it.next());
}

这篇关于在Spliterator的.tryAdance()实现中,是否存在使用.accept()多个元素的危险?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆