【问题标题】:is i >= elementData.length in ArrayList::iterator redundant?ArrayList::iterator 中的 i >= elementData.length 是多余的吗?
【发布时间】:2016-11-09 10:45:31
【问题描述】:

这是 ArrayList::Itr 的下一个方法

public E next() {
    checkForComodification();
    int i = cursor;
    if (i >= size)
        throw new NoSuchElementException();
    Object[] elementData = ArrayList.this.elementData;
    if (i >= elementData.length)
        throw new ConcurrentModificationException();
    cursor = i + 1;
    return (E) elementData[lastRet = i];
}

它包含一个 if 语句:

if (i >= elementData.length)
    throw new ConcurrentModificationException();

我认为这种情况很少发生i >= elementData.length,除非用户调用 trimToSize 方法。而且我认为 if 语句是多余的,因为 checkForComodification 可以处理所有事情。 我说的对吗?

【问题讨论】:

  • 我认为您的意思不是“丰富”……因为它没有意义。你的意思是“冗余”吗?
  • 是的,非常感谢。
  • “我说的对吗?” 不,因为你不能保证,在checkForComodification 调用之后,if (i >= elementData.length) 之前不会操纵内容.你会发现很多情况,当你用谷歌搜索 "java ConcurrentModificationException iterator".

标签: java arraylist iterator next


【解决方案1】:

不,不是。如果使用另一个线程,则在

之后使用了 ArrayListtrimTosize
checkForComodification();

...但是之前

Object[] elementData = ArrayList.this.elementData;

ArrayList.this.elementData 在此期间可能已更改(收到新的数组引用)。因此,在将ArrayList.this.elementData 抓取到局部变量(elementData) 之后 检查数组中的索引是否有效是正确且必要的。代码完成此操作后,它具有对将要查找的数组的局部引用 (elementData) 和索引的局部变量 i)。如果在代码抓取之前更改为 ArrayList.this.elementData 导致索引无效,则此时需要该代码才能引发正确的异常 (ConcurrentModificationException) 而不是 ArrayIndexOutOfBounds

例如,注意** 行:

    public E next() {
        checkForComodification();
        int i = cursor;                                    // ***
        if (i >= size)                                     // ***
            throw new NoSuchElementException();            // ***
        Object[] elementData = ArrayList.this.elementData; // ***
        if (i >= elementData.length)
            throw new ConcurrentModificationException();
        cursor = i + 1;
        return (E) elementData[lastRet = i];
    }

另一个线程可能会进入那里。只有当我们对将要使用的数组有自己的引用时(在最后一行 ** 完成后),我们才知道引用不会改变(因为它是本地的)。

【讨论】:

  • 我认为您的回答部分正确。确实,如果没有“i >= elementData.length”检查,ArrayIndexOutOfBounds 可能会发生。但是,这个检查不能保证 ArrayIndexOutOfBounds 永远不会发生,因为 elementData 的大小也可能在“cursor = i + 1;”之后,在另一个线程“return”之前改变。所以,我认为检查长度是没有意义的。不是吗?
  • @expoter:不,不可能。数组的内容是可变的,但数组的长度不是。从我指出的Object[] elementData = ArrayList.this.elementData; 行开始,我们知道我们的本地elementData 变量不能引用if (i >= elementData.length)return (E) elementData[lastRet = i]; 之间的不同数组我们还知道i 不能被另一个线程更改。不过,在该行之前,ArrayList.this.elementData 可以 更改为指向不同的数组。所以检查是必要和充分的。
  • 哦,我明白了。谢谢。
【解决方案2】:

假设您的意思是“冗余”而不是“丰富”,那么不,它不是。

在调用checkForComodification() 之后有一个小窗口,在该窗口中可以更改数组的大小,因为另一个线程已经调整了ArrayList 的大小。发生这种情况的可能性非常小,但如果没有此检查,next() 调用可能会抛出 ArrayIndexOutOfRangeException


另一方面,next() 代码不能保证检测到所有并发修改。如果其他线程在checkForComodification() 调用之后设法将元素添加到列表中,则该修改将不会被检测到。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-01-07
    • 2018-04-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多