java - iterator.next() 可以从源中删除元素吗? ( java )

标签 java iterator

有一个Java函数

public <T> void batchWrite(Iterable<T> source, int number)

以省时的方式写入大量项目。

我想在 ConcurrentLinkedQueue 上使用此 batchWrite(),它可以在 batchWrite() 工作时写入。我希望 batchWrite() 删除它从队列中取出的项目。

我可以编写一个迭代器(并将其包装到一个 Iterable 中)来删除返回的项目:

class IteratorThatRemovesReturnedValues<T> implements Iterator<T> {
    Queue<T> queue;
    IteratorThatRemovesReturnedValues(Queue<T> q) { queue = q; }
    boolean hasNext() { return queue.peek() != null; }
    T next() { return queue.poll(); }
}

问题是:这不会是对概念的滥用吗?

remove() 的描述说: 如果在迭代过程中以除调用此 (remove()) 方法以外的任何方式修改基础集合,则迭代器的行为是未指定的。 这可以用任何一种方式来理解:Iterator 的特定实现可以允许也可以不允许定义以某种特定方式修改底层无等待队列时发生的情况。

从底层队列中移除返回的元素是否会与迭代器的约定相矛盾?

(另一种方法是将一定数量的项目poll() 放入辅助ArrayList 并在该列表上调用batchWrite()。)

编辑这个问题的另一面:迭代器可以由管道支持吗?

最佳答案

假设您没有考虑 Iterator#remove() 方法的(许多)注意事项,根据约定,迭代器的行为很简单。特别是,它没有说明任何底层实现。

旁注:历史上,IteratorCollection 的迭代相关联,但这可能只是对遗留 Enumeration 的一种补救措施> 类。有许多Iterator 实现与集合相关。 (例如,Scanner 等等)。如今,Iterator 通常不过是一个“允许您查询是否有更多可用的事物的抽象来源”

但严格来说,您的实现已经遵守契约。 Iterator#next() method 的文档说:

Throws:

NoSuchElementException - if the iteration has no more elements

这不是你的情况。您的实现将在此处简单地返回 null。当然,这可以通过调用 remove() 替换 poll() 调用来轻松缓解,这会很方便地抛出 NoSuchElementException ,但我想这会与您当前的目标相矛盾。

我认为关键点是您对 next() 方法的实现有一个对外界可见的副作用。评论中已经给出了一个示例:当您创建两个这样的迭代器实例时,两者都可能会根据它们的约定行为,但两者的行为可能与预期的不同。

后者仅指单线程使用。当两个线程独立使用这些迭代器时,对 hasNext()next() 的交织调用可能会引发竞争条件。 (当两个线程使用单个迭代器时甚至更多,但所有迭代器都是这种情况,因为它们通常无论如何都是有状态的)。


底线是:尽管预期用途的一些细节仍然不清楚(特别是关于迭代器在 batchWrite 方法中究竟如何使用的问题,以及多线程应该如何使用的问题在这里进行交互),这种实现方式迟早会失效,bug 很难检测和重现。我建议在这里考虑替代实现。

关于java - iterator.next() 可以从源中删除元素吗? ( java ),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38370548/

相关文章:

java - 如何解决 : Error:Execution failed for task ':app:kaptDebugKotlin' ?

typescript - 类型 'HTMLCollectionOf<HTMLCanvasElement>' 必须有一个返回迭代器的 '[Symbol.iterator]()' 方法

C++:用于超重对象的方便的基于指针数组的值迭代器

c++ - 在列表中查找最常见的元素(C++ STL)?

java - 如何获取已加载的 JNI 库列表?

java - MainActivity 中的 Android Map Fragment 不调用 onMapReady

java - Hibernate Cascade 来自另一个数据库的另一个 ID

c++ - 将一个容器的迭代器复制到另一个迭代器容器中,然后再从第一个容器中删除它

c++ - 迭代某个类的 vector 列表 (C++)

java - 是否可以将字符串附加到 Android Activity 标题栏?