Home > Software design >  Why doesn't the rangeCheck method in the java.util.ArrayList class check for negative index?
Why doesn't the rangeCheck method in the java.util.ArrayList class check for negative index?

Time:03-01

/**
 * 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));
}

From: jdk/ArrayList.java at jdk8-b120 · openjdk/jdk · GitHub

If we write the following code, both indexes are out of bounds, but the exception types are different.

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();
        }
    }

}

The output is as follows:

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)

Related question:

  • Why does rangeCheckForAdd method in the java.util.ArrayList check for negative index?
  • Why doesn't java.util.Arrays.ArrayList do index out-of-bounds checking?

What confuses me is why their implementations are inconsistent? Are these methods written by different people with their own programming style? In other words, if out-of-bounds exceptions will eventually fire, then there is no need to check.

CodePudding user response:

It's a micro-optimization. For code clarity you might prefer the same exception for both, but when you're in a hot loop you'll want to avoid an unnecessary operation. ArrayList being an old class, the effect this has may have varied between times and JDK versions. If someone has enough interest they could benchmark it with 1.8 and newer JDKs to see how much of an optimization it is for get().

Since accessing a negative array index will fail anyway, there is no need to check for it. However the size of the ArrayList is not always the same as the size of its internal array, so it needs to be checked explicitly.

As to why rangeCheckForAdd does check for negative indexes, good question. Adding is slow anyway, so the micro-optimization wouldn't make much of a difference. Maybe they wanted consistent error messaging here.

CodePudding user response:

The range check on the array access checks if the array index is in the range 0 <= index < elementData.length.

For a java.util.ArrayList the valid range of indexes is only 0 <= index < size, with size <= elementData.length. Since the array access cannot correctly check the upper bound (size could be less then elementData.length) the ArrayList class has to make sure that the upper bound is not violated.

The lower bound doesn't need to be checked because the lower bound is always 0 and is validated when the elementData array is accessed.


Why does rangeCheckForAdd check for negative index?

When adding elements it can be necessary to grow the size of the elementData array before the new element is added. But if the index is invalid (negative or greater than size) you don't want to grow the elementData array. In this case it is therefore necessary to do the complete bounds check (0 <= index <= size) before anything else is done.


Why doesn't java.util.Arrays.ArrayList do out of bounds checking?

The size of a java.util.Arrays.ArrayList is exactly the size of the backing array. A separate bounds check (as in the of the java.util.ArrayList, where size can be smaller then the size of the backing array) is therefore not required.

  • Related