JAVA • COLLECTIONS AND STRINGS

Array Access & Bounds — Access and update array elements; avoid out-of-bounds errors

Master how Java arrays store data in numbered slots and learn to prevent the dreaded ArrayIndexOutOfBoundsException.

Historical Context & Motivation

Before modern programming languages existed, early computers stored data in sequential blocks of memory. Scientists and engineers needed a way to organize related values — like a series of sensor readings or a list of student scores — so they could be processed efficiently. The concept of the array emerged as one of the oldest and most fundamental data structures in computing. An array gives each element a numbered position, called an index, making it possible to jump directly to any value without scanning through the entire collection.

1950s
Fortran Introduces Arrays
IBM's Fortran language became one of the first high-level languages to offer built-in array support, allowing scientists to process numerical tables efficiently.
1972
C Popularizes Zero-Based Indexing
The C programming language adopted zero-based indexing because array names map directly to memory addresses, making index 0 the natural starting offset.
1995
Java Adds Bounds Checking
Java inherited zero-based arrays from C but added automatic bounds checking at runtime, throwing an ArrayIndexOutOfBoundsException instead of allowing silent memory corruption.
2004+
Enhanced For-Loops & Collections
Java 5 introduced the enhanced for-each loop and generics for Collections, giving programmers safer patterns to iterate over arrays and lists without manual index management.

Despite decades of improvements, one of the most common bugs in student code — and in professional software — remains the off-by-one error. Understanding how array indices work and where their boundaries lie is essential for writing correct, reliable Java programs. This lesson gives you the tools to access and update array elements confidently while steering clear of out-of-bounds crashes.

Core Principles & Definitions

An array in Java is a fixed-size container that holds elements of the same type. Every element sits at a specific position determined by its integer index. Before you can read or change any element, you need to understand a handful of foundational rules that Java enforces.

1

Zero-Based Indexing

The first element of every Java array lives at index 0, the second at index 1, and so on. If an array has n elements, the last valid index is n − 1.
2

Fixed Length

Once you create an array with new int[5], its length is permanently 5. You cannot add or remove slots. The .length property tells you how many slots exist.
3

Access with Bracket Notation

Use arr[i] to read the value at index i, and arr[i] = value to update it. Both operations happen in constant time.
4

Bounds Checking at Runtime

Java automatically checks that your index is ≥ 0 and < arr.length every time you access an element. An invalid index triggers an ArrayIndexOutOfBoundsException.
5

Default Values

When you create an array, Java fills every slot with a default: 0 for numeric types, false for booleans, and null for object references.
✦ KEY TAKEAWAY
Think of a Java array like a row of numbered lockers in a school hallway. The lockers are numbered starting from 0, not 1. If there are 10 lockers, the last one is locker number 9. Trying to open locker 10 means you've walked past the end of the hallway — Java stops you with an exception rather than letting you open someone else's locker.

Visual Explanation — Array Memory Layout

The diagram below shows a Java array of five integers declared as int[] scores = {88, 92, 75, 100, 64};. Each colored box represents one slot in memory. Notice that the indices run from 0 to 4 — never reaching 5, even though the array length is 5. The red zone beyond index 4 marks the out-of-bounds region that would trigger an exception.

Each colored cell maps an index (top row) to its stored value (bottom row). The green bar confirms the valid range, while the red dashed zone illustrates what happens when you use a negative index or an index equal to or greater than the array's length.

The key insight from this diagram is the relationship between length and the maximum valid index. Because Java counts from zero, the last valid index is always length − 1. This single fact prevents most out-of-bounds errors once you internalize it. Every time you write a loop or compute an index, ask yourself: "Is this value between 0 and length − 1, inclusive?"

How Array Access Works Under the Hood

When Java allocates an array, it reserves a contiguous block of memory. The variable name (like scores) stores a reference pointing to the start of this block. Accessing scores[i] tells the JVM to jump forward by i positions from the beginning. Because every element is the same size, this calculation is instant — the JVM doesn't need to scan through earlier elements.

MEMORY ADDRESS FORMULA
address(i) = baseAddress + i × elementSize
baseAddress is where the array data starts in memory. i is the index you supply. elementSize is the number of bytes per element (e.g., 4 bytes for an int). This formula explains why index 0 lands exactly at the base — 0 × anything is 0.
VALID INDEX CONSTRAINT
0 ≤ i < array.length
The index i must be greater than or equal to 0 and strictly less than the array's length. Note the strict inequality on the right: the index must be less than the length, never equal to it.

Common Access Patterns

Reading an element is straightforward: int x = scores[2]; copies the value at index 2 into the variable x. Updating is equally direct: scores[2] = 80; replaces the old value with 80. Both operations complete in constant time — O(1) — regardless of the array's size. This speed is one of the main advantages arrays have over other data structures.

⚠ Watch Out: Common Off-By-One Mistakes
The two most frequent errors are using arr[arr.length] (one past the end) and using <= instead of < in a for-loop condition. Both of these try to reach a slot that doesn't exist.

Iterating Safely — Loop Patterns & Pitfalls

Most array work happens inside loops. Getting the loop boundaries right is the single most important skill for avoiding out-of-bounds exceptions. Let's compare the three main iteration styles in Java and identify where mistakes tend to hide.

The top row shows three correct loop patterns. The red boxes below highlight the two most common bugs: using <= instead of <, and starting the index at 1 instead of 0. The green rule at the bottom summarizes the safe default.

The for-each loop is the safest option when you don't need the index at all, because it eliminates the possibility of an off-by-one error entirely. However, if you need to modify elements in place or need to know which position you're at, the standard for loop is essential. Just remember: start at 0, use < (not <=), and compare against arr.length.

Comparison of Java array loop patterns
Loop StyleWhen to UseBounds Risk
for (int i = 0; i < arr.length; i++)Need the index (e.g., modifying elements, comparing neighbors)Medium — must get condition right
for (int val : arr)Only reading values; index not neededLow — no manual index
while (i < arr.length)Complex stopping conditions or variable step sizesHigher — must remember to increment

Worked Example — Finding the Maximum Value

Let's walk through a complete example that accesses every element of an array while carefully staying within bounds. We'll find the maximum value in an array of test scores.

Find the Maximum Score
1
Step 1 — Declare and Initialize the ArrayWe start by creating an array of six integers representing test scores: int[] scores = {78, 95, 63, 88, 100, 72};. The array has a length of 6, so valid indices range from 0 to 5.
scores.length = 6, valid indices: 0 through 5
2
Step 2 — Set an Initial MaximumWe initialize a variable int max = scores[0]; to hold the first element as our starting guess. This is safe because we know the array is not empty.
max = 78 (the value at index 0)
3
Step 3 — Loop from Index 1 to length − 1We write for (int i = 1; i < scores.length; i++). We start at 1 (because we already used index 0) and stop before 6. Inside the loop, we compare scores[i] to max and update max if the current score is larger.
Loop runs with i = 1, 2, 3, 4, 5 — all valid
4
Step 4 — Trace Through the Iterationsi=1: scores[1]=95 > 78 → max becomes 95. i=2: 63 < 95 → no change. i=3: 88 < 95 → no change. i=4: scores[4]=100 > 95 → max becomes 100. i=5: 72 < 100 → no change. The loop ends when i reaches 6, which is not less than scores.length, so the condition i < 6 is false and we stop safely.
max = 100
5
Step 5 — Print the ResultSystem.out.println("Highest score: " + max); outputs Highest score: 100. No out-of-bounds exception occurred because the loop respected the constraint 0 ≤ i < length.
Output: Highest score: 100

Common Pitfalls vs. Best Practices

Now that you know how array access works, let's compare the mistakes programmers commonly make with the best practices that prevent them. Understanding both sides will help you spot errors in your own code and in code reviews.

Pitfalls and their corresponding best practices
Common PitfallBest PracticeWhy It Matters
Using i <= arr.length as the loop conditionUse i < arr.length — strict less thanThe index equal to length is one past the last slot, causing an exception on the final iteration.
Hard-coding the array size in the loop condition (e.g., i < 5)Always use arr.length so the loop adapts if the size changesIf you later change the array size and forget to update the magic number, you get a bug or a crash.
Accessing arr[i + 1] inside a loop that runs to arr.length − 1Stop the loop at arr.length − 2 when using arr[i + 1]When i is at the last valid index, i + 1 is out of bounds. Shorten the loop by one iteration.
Assuming user-supplied indices are valid without checkingValidate with if (index >= 0 && index < arr.length) before usingDefensive programming prevents runtime crashes from unexpected input.
Forgetting that an empty array (length 0) has no valid indices at allCheck if (arr.length > 0) before accessing arr[0]Even index 0 is out of bounds for an empty array.
✦ KEY TAKEAWAY
Think of the array's valid index range like a speed limit sign. You can drive at any speed from 0 up to the limit minus one. The .length property is the sign itself — it tells you the limit, but driving at exactly that number already puts you over the edge. Always use strictly less than when comparing against length.

Arrays vs. ArrayLists and Beyond

Java arrays are powerful but limited by their fixed size. As your programs grow more complex, you'll encounter the ArrayList class, which wraps an internal array and handles resizing automatically. Understanding how plain arrays work gives you the foundation to understand every other collection in Java, because most of them use arrays under the hood.

Arrays vs. ArrayLists at a glance
FeatureArray (int[])ArrayList<Integer>
SizeFixed at creationGrows and shrinks dynamically
Access syntaxarr[i]list.get(i)
Update syntaxarr[i] = vallist.set(i, val)
Length propertyarr.lengthlist.size()
Out-of-bounds exceptionArrayIndexOutOfBoundsExceptionIndexOutOfBoundsException
Can store primitives directly?YesNo — must use wrapper classes like Integer

Notice that the same zero-based indexing and the same bounds-checking logic apply to ArrayLists. If you internalize the rule "valid indices run from 0 to size − 1" now, it will transfer directly to every list-based structure you encounter in the future, including Strings (where charAt(i) follows exactly the same constraint).

🔭 Looking Ahead
In AP Computer Science A, you'll work with 2D arrays where bounds checking becomes even more critical — you'll need to validate both the row index and the column index separately. The principles you're learning here apply to every dimension.

Practice Problems

PROBLEM 1 — CONCEPTUAL
An array is declared as String[] names = new String[8];. What is the index of the first element, and what is the index of the last element? Explain why names[8] would cause an error.
PROBLEM 2 — BASIC CALCULATION
Given int[] vals = {10, 20, 30, 40, 50};, what is the value of vals[1] + vals[vals.length - 1]? Show your reasoning step by step.
PROBLEM 3 — INTERMEDIATE
The following code is supposed to swap the first and last elements of an array. Identify the bug and fix it: int[] data = {5, 10, 15, 20}; data[0] = data[data.length]; data[data.length] = data[0];
PROBLEM 4 — APPLIED
A teacher stores daily attendance counts in an array: int[] attendance = {28, 30, 27, 29, 30}; (one entry per day of the week, Monday through Friday). Write a loop that computes the average daily attendance. Make sure your loop does not risk an out-of-bounds error, and explain why.
PROBLEM 5 — CRITICAL THINKING
A method receives an array and needs to check whether any two consecutive elements are equal. A student writes: for (int i = 0; i < arr.length; i++) { if (arr[i] == arr[i + 1]) { return true; } } Explain what goes wrong, fix the code, and then explain what additional edge case should be handled if the array could be empty or have only one element.

Lesson Summary

Java arrays use zero-based indexing, meaning the first element lives at index 0 and the last element at index length − 1. You access and update elements using bracket notation — arr[i] to read and arr[i] = value to write — both of which happen in constant time. Java's automatic bounds checking throws an ArrayIndexOutOfBoundsException whenever an index falls outside the range 0 ≤ i < length.

To stay safe, always use strict less-than (<) when comparing a loop variable against arr.length, prefer the for-each loop when you don't need the index, and shorten loops by one when accessing arr[i + 1]. These patterns carry over directly to ArrayLists, Strings, and 2D arrays — mastering bounds safety here sets you up for success throughout your Java journey.

Varsity Tutors • Java • Array Access & Bounds