161 lines
4.8 KiB
Plaintext
161 lines
4.8 KiB
Plaintext
|
|
An array index out-of-bounds exception is a bug class that occurs in Java when a
|
|
program tries to access an array element that does not exist.
|
|
This bug can cause your program to crash or behave unexpectedly.
|
|
To fix an array index out of bounds exception in Java, you should always ensure
|
|
that you are accessing array elements within the bounds of the array.
|
|
|
|
|
|
== Why is this an issue?
|
|
|
|
An array index out-of-bounds exception indicates a bug or a logical error in the
|
|
code.
|
|
|
|
In Java, arrays have a fixed size, and their elements are indexed starting from
|
|
`0`, counting up to the last index that is still smaller than the size.
|
|
When trying to access an array outside of this range, an
|
|
`ArrayIndexOutOfBoundsException` will be thrown and the operation will fail.
|
|
|
|
include::../impact.adoc[]
|
|
|
|
== How to fix it
|
|
|
|
=== Code examples
|
|
|
|
The following examples contain out-of-bounds accesses to arrays, resulting
|
|
in `ArrayIndexOutOfBounds` exceptions.
|
|
These situations can be avoided by carefully considering the range of valid
|
|
index values, or even better, by comparing indices against the size of a
|
|
sequence.
|
|
|
|
In this first example, the array `arr` contains three elements.
|
|
Since the first element of a list has index `0`, the last valid index is `2`.
|
|
Therefore, an `ArrayIndexOutOfBoundsException` is thrown when accessing `arr` at
|
|
index `3`.
|
|
|
|
==== Noncompliant code example
|
|
|
|
[source,java,diff-id=1,diff-type=noncompliant]
|
|
----
|
|
void fun() {
|
|
int[] arr = {1, 2, 3};
|
|
|
|
int x = arr[3]; // Noncompliant: Valid indices are 0, 1 and 2
|
|
}
|
|
----
|
|
|
|
==== Compliant solution
|
|
|
|
[source,java,diff-id=1,diff-type=compliant]
|
|
----
|
|
void fun() {
|
|
int[] arr = {1, 2, 3};
|
|
|
|
int x = arr[0];
|
|
}
|
|
----
|
|
|
|
Accessing an array with its size as the index is never correct:
|
|
|
|
==== Noncompliant code example
|
|
|
|
[source,java,diff-id=2,diff-type=noncompliant]
|
|
----
|
|
void fun(int[] arr) {
|
|
System.out.println(arr[arr.length]); // Noncompliant: Indexing starts at 0, hence array.length will always be an invalid index.
|
|
}
|
|
----
|
|
|
|
==== Compliant solution
|
|
|
|
[source,java,diff-id=2,diff-type=compliant]
|
|
----
|
|
void compliant(int[] arr) {
|
|
// We can make sure arr is non-empty before trying to access its last element.
|
|
if (arr.length > 0) {
|
|
System.out.println(arr[arr.length - 1]);
|
|
} else {
|
|
System.out.println("Empty array!");
|
|
}
|
|
}
|
|
----
|
|
|
|
=== How does this work?
|
|
|
|
You should always ensure that you are accessing arrays using indices that are
|
|
within the bounds of the array.
|
|
Here are some best practices to follow:
|
|
|
|
Always compare indices against the length of an array using `if-else` statements
|
|
or other control flow constructs before accessing elements.
|
|
For this, you can use the `length` property of arrays.
|
|
For example, `arr.length` returns the length of the `arr` array.
|
|
Also, ensure that you are not accessing an array using negative indices.
|
|
|
|
Use loops to iterate over arrays instead of accessing elements directly.
|
|
This can be done using the `for` loop or the `foreach` loop.
|
|
For example, `for (int i = 0; i < arr.length; ++i)` iterates over the `arr`
|
|
array within its bounds using an index variable `i`.
|
|
The same goes for `for (Object o : arr)`.
|
|
If you manipulate the index used to access an array inside the loop, make sure
|
|
that the resulting index stays within bounds.
|
|
|
|
=== Pitfalls
|
|
|
|
The indices `0`, or `arr.length - 1` for the first and last element of an array
|
|
are not always valid!
|
|
Make sure the array in question is not empty before accessing these indices.
|
|
|
|
=== Going the extra mile
|
|
|
|
In many cases you can eliminate loops containing index-based accesses altogether
|
|
by applying the Java stream API to arrays using `java.util.Arrays.stream()`.
|
|
The API provides methods like `map()` or `filter()` that allow you to transform,
|
|
filter and perform many different operations on the elements of an array without
|
|
using indices.
|
|
|
|
|
|
== Resources
|
|
|
|
=== Documentation
|
|
|
|
* https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/ArrayIndexOutOfBoundsException.html[ArrayIndexOutOfBoundsException]
|
|
* https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/Arrays.html#stream(T%5B%5D)[Javadoc for `Arrays.stream()`]
|
|
* https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/stream/Stream.html[Stream API]
|
|
|
|
=== Articles & blog posts
|
|
|
|
* A Reference Guide - https://www.baeldung.com/java-arrays-guide[Arrays in Java]
|
|
|
|
=== Standards
|
|
|
|
* https://docs.oracle.com/javase/specs/jls/se17/html/jls-10.html#jls-10.4[Array Access Specification]
|
|
|
|
|
|
ifdef::env-github,rspecator-view[]
|
|
|
|
'''
|
|
== Implementation Specification
|
|
(visible only on this page)
|
|
|
|
=== Message
|
|
|
|
Fix this access on an array element that may trigger an 'ArrayIndexOutOfBoundsException'.
|
|
|
|
'''
|
|
|
|
endif::env-github,rspecator-view[]
|
|
|
|
|
|
|
|
//=== How does this work?
|
|
|
|
//=== Pitfalls
|
|
|
|
//=== Going the extra mile
|
|
|
|
//=== Articles & blog posts
|
|
//=== Conference presentations
|
|
//=== Standards
|
|
//=== Benchmarks
|