[google/guava]修复使用 Lists.partition 并删除时出现 NoSuchElementException 的问题 #3790

2024-07-16 291 views
9

NoSuchElementException 发生是因为 AbstractList 中的 Iterator 调用 hasNext() 如下

public boolean hasNext() {
            return cursor != size();
        }

但是在 List 上执行 remove 操作后,调用 size() 的结果会发生变化。因此我将 size 设为 final int listSize。

回答

5

我在本地测试了我的提交。但没有在提交中添加测试。如果需要,我将在将来添加测试。

9

从#3790 的讨论来看,听起来,如果有的话,我们想要hasNext()抛出一个ConcurrentModificationException

2

@cpovirk 嗨,我已查看了讨论。但我认为预期的行为不应该引发异常。

根据讨论,他们对iter.hasNext()为何为真感到困惑。实际上,这是因为Partition类使用了超类AbstractList中的Iterator。而AbstractList类中的hasNext()函数并不完善。它们已在子类ArrayList中进行了优化。请在下面查看

这是AbstractList类中的hasNext。它调用size()函数

public boolean hasNext() {
    return cursor != size();
} 

这是ArrayList类中的hasNext。它使用值 size。文档说它是AbstractList.Itr 的优化版本。我在 JDK1.8 中看到了这个

public boolean hasNext() {
    return cursor != size;
}

当使用函数size()时,每次程序调用hasNext()hasNext()会调用size(),然后size 的值会被重新计算。回到 #3570 的代码,当程序执行removeall()时,重新计算的 size 会是 0,但是游标是 1。所以hasNext()返回 true。

示例代码见#3570

for(List<Integer> l : ll){
   l.removeAll(elementExclude);
}

因此我引入了listsize来保存该值,以确保它只被计算一次。

我还测试了下面的代码。我使用 ArrayList 作为容器,然后执行相同的removeAll操作。没有抛出任何异常。所以,我认为分区的行为应该相同

        List<Integer> list = new ArrayList();
        list.add(1);
        List<Integer> elementExclude = new ArrayList();
        elementExclude.add(1);

        List<List<Integer>> ll = new ArrayList();

        ll.add(list);
        for(List<Integer> l : ll){

            l.removeAll(elementExclude);
        }
2

拼写错误:3790,不是 3570

1

让我们整合其他帖子中的讨论。如果就该怎么做达成一致,我们可以重新打开此帖子(或新的 PR)。

7

@cpovirk 好的,我会在 #3790 中与他们讨论我的想法。无论如何,谢谢