为什么 java.util.ArrayList 类中的 rangeCheck 方法不检查负索引?[关闭]

Why doesn't the rangeCheck method in the java.util.ArrayList class check for negative index? [closed]

提问人:Poison 提问时间:2/28/2022 最后编辑:Poison 更新时间:2/28/2022 访问量:556

问:


想改进这个问题吗?更新问题,以便可以通过编辑这篇文章用事实和引文来回答。

去年关闭。

/**
 * Checks if the given index is in range.  If not, throws an appropriate
 * runtime exception.  This method does *not* check if the index is
 * negative: It is always used immediately prior to an array access,
 * which throws an ArrayIndexOutOfBoundsException if index is negative.
 */
private void rangeCheck(int index) {
    if (index >= size)
        throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}

来自: jdk/ArrayList.java at jdk8-b120 · openjdk/jdk ·GitHub的

如果我们编写以下代码,则两个索引都越界,但异常类型不同。

import java.util.ArrayList;
import java.util.List;

public class Test {

    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("");

        try {
            list.get(-1);
        } catch (Exception e) {
            e.printStackTrace();
        }

        try {
            list.get(1);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

输出如下:

java.lang.ArrayIndexOutOfBoundsException: -1
    at java.util.ArrayList.elementData(ArrayList.java:424)
    at java.util.ArrayList.get(ArrayList.java:437)
    at Test.main(Test.java:11)
java.lang.IndexOutOfBoundsException: Index: 1, Size: 1
    at java.util.ArrayList.rangeCheck(ArrayList.java:659)
    at java.util.ArrayList.get(ArrayList.java:435)
    at Test.main(Test.java:17)

相关问题:

  • 为什么方法在检查负指数?rangeCheckForAddjava.util.ArrayList
  • 为什么不进行索引越界检查?java.util.Arrays.ArrayList

让我感到困惑的是为什么它们的实现不一致?这些方法是由不同的人编写的,有自己的编程风格吗?换句话说,如果最终会触发越界异常,则无需检查。

Java ArrayList 索引OutofboundsException 防御性编程

评论

0赞 ControlAltDel 2/28/2022
什么是ArrayList.rangeCheckForAdd()?
0赞 ControlAltDel 2/28/2022
什么是java.util.Arrays.ArrayList??
0赞 ControlAltDel 2/28/2022
无论如何。ArrayList 的实现方式是 Sun / Oracle 的编程团队选择的方式。老实说,答案就这么简单
1赞 user16320675 2/28/2022
“为什么 ArrayList.rangeCheck() 不检查负索引?”答案就在源代码注释中:“它总是在数组访问之前立即使用,如果索引为负数,则会抛出 ArrayIndexOutOfBoundsException。
1赞 user16320675 2/28/2022
我没有实现也没有参与开发 - 我的评论是回答标题中的问题(并且仅基于发布的评论) - 也许这个问题应该在 Java 开发人员的一些邮件列表中提出raneCheckForAdd

答:

3赞 Kayaman 2/28/2022 #1

这是一个微优化。为了代码清晰起见,您可能希望两者使用相同的例外,但是当您处于热循环中时,您需要避免不必要的操作。 作为一个旧类,其效果可能因时代和 JDK 版本而异。如果有人有足够的兴趣,他们可以用 1.8 和更新的 JDK 对其进行基准测试,看看它对优化有多大。ArrayListget()

由于访问负数组索引无论如何都会失败,因此无需检查它。但是,的大小并不总是与其内部数组的大小相同,因此需要显式检查。ArrayList

至于为什么要检查负指数,好问题。无论如何,添加速度很慢,因此微优化不会有太大区别。也许他们希望在这里保持一致的错误消息。rangeCheckForAdd

评论

0赞 Poison 3/1/2022
经过一番搜索,我发现在 JDK 9 提交中,该实现已被替换为检查负数并使用 JVM 方法内联。请参见: 8079136:访问嵌套子列表会导致 StackOverflowError · openjdk/jdk@763f489 ·GitHub的
4赞 Thomas Kläger 2/28/2022 #2

对数组访问的范围检查检查数组索引是否在范围 中。0 <= index < elementData.length

对于 a,索引的有效范围仅为 ,其中 。由于数组访问不能正确检查上限(可能小于 ),因此类必须确保不违反上限。java.util.ArrayList0 <= index < sizesize <= elementData.lengthsizeelementData.lengthArrayList

不需要检查下限,因为下限始终在访问数组时进行验证。0elementData


为什么 rangeCheckForAdd 检查负索引?

添加元素时,可能需要在添加新元素之前增加数组的大小。但是,如果索引无效(负数或大于大小),则不希望增加数组。因此,在这种情况下,有必要在执行其他任何操作之前进行完整的边界检查()。elementDataelementData0 <= index <= size


为什么 java.util.Arrays.ArrayList 不进行越界检查?

a 的大小正好是后备数组的大小。因此,不需要单独的边界检查(如 ,其中大小可以小于后备数组的大小)。java.util.Arrays.ArrayListjava.util.ArrayList