Junior 4 min · March 05, 2026

Java Arrays — Why <= Crashed 2.4 Million Records

One character difference: < vs <= in array loops.

N
Naren Founder & Principal Engineer

20+ years shipping production Java in banking & fintech. Written from production experience, not tutorials.

Follow
Production
production tested
May 24, 2026
last updated
1,554
articles · all by Naren
 ● Production Incident 🔎 Debug Guide ⚙ Triage Commands
Quick Answer
  • Java array = fixed-size contiguous memory block holding same-type elements. Accessed by zero-based index: arr[0] first, arr[length-1] last
  • Key components: declaration (int[] scores), creation (new int[5]), initialization ({1,2,3}), length property (scores.length)
  • Performance: O(1) access via address calculation (base + index * element_size). Sequential iteration is cache-friendly (~10x faster than linked structures)
  • Production trap: ArrayIndexOutOfBoundsException caused by using <= instead of < in loop condition — compiles fine, crashes at runtime
  • Biggest mistake: Printing array directly — System.out.println(scores) prints memory address [I@6d06d69c, not the contents
✦ Definition~90s read
What is Arrays in Java?

Java arrays are fixed-length, zero-indexed containers that store elements of a single type in contiguous memory. They exist because the JVM needs a predictable, cache-friendly data structure for fast random access — O(1) by index — without the overhead of dynamic resizing or boxing.

Imagine you're organising a egg carton.

You create them with new int[10] or the shorthand {1, 2, 3}, but the length is set at creation and never changes. This rigidity is both their strength and their danger: you get raw speed and memory locality, but you must track bounds yourself. Alternatives like ArrayList or LinkedList trade that speed for flexibility, so arrays are best when you know the exact size upfront and need maximum performance — think high-frequency trading systems or embedded JVMs where every nanosecond counts.

The infamous ArrayIndexOutOfBoundsException is the price of that contract, and as the title suggests, a single off-by-one error in a loop can silently corrupt millions of records when writing to a database or file, because Java trusts you to stay within bounds and offers no runtime guardrails beyond the exception itself.

Plain-English First

Imagine you're organising a egg carton. Instead of having 12 loose eggs rolling around your kitchen counter, the carton holds all 12 in one neat, numbered container — slot 0 through slot 11. A Java array is exactly that carton: one named container that holds a fixed number of values, all of the same type, each sitting in a numbered slot you can reach instantly. No more juggling 12 separate variables.

A Java array is a fixed-length container that holds elements of a single type, indexed from zero. Without it, you’re manually juggling variables or dragging in heavyweight collections for simple sequential data. Misunderstand the reference model or the bounds, and you’ll face null pointers, silent data corruption, or runtime exceptions. This article covers exactly what an array is, how to walk through it efficiently, and why 2D arrays are just arrays of arrays.

What an Array Actually Is — And How to Create One

An array is a fixed-size, ordered container that holds multiple values of the same data type under a single variable name. 'Fixed-size' is the crucial word here — once you create an array with 5 slots, it has exactly 5 slots forever. You can't shrink it or stretch it later. This is a deliberate design decision: by locking the size upfront, Java can reserve one continuous block of memory, which makes reading and writing values extremely fast.

Every slot in the array has an index — a number that tells you its position. Arrays in Java are zero-indexed, meaning the first slot is index 0, not 1. So a 5-element array has indices 0, 1, 2, 3, and 4. That last index is always length minus one — a detail that trips up almost every beginner at least once.

There are two ways to create an array: declare and allocate separately, or declare and initialise in one shot with values you already know. Both are shown below.

io/thecodeforge/java/arrays/ArrayCreation.javaJAVA
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
package io.thecodeforge.java.arrays;

public class ArrayCreation {
    public static void main(String[] args) {

        // --- WAY 1: Declare the array, then fill in the values yourself ---
        // This creates an integer array with exactly 5 slots.
        // Right now every slot holds 0 (Java fills numeric arrays with 0 by default).
        int[] highScores = new int[5];

        // Now we assign values to each slot using its index (0-based)
        highScores[0] = 9500;   // first slot
        highScores[1] = 8750;
        highScores[2] = 8200;
        highScores[3] = 7600;
        highScores[4] = 5100;   // fifth (last) slot — index 4, NOT 5

        // --- WAY 2: Declare AND initialise in one line ---
        // Use this when you already know all the values up front.
        // Java counts the values and sets the size automatically.
        String[] daysOfWeek = {"Monday", "Tuesday", "Wednesday", "Thursday", "Friday"};

        // Reading a value back: use the variable name + [index]
        System.out.println("Top score:      " + highScores[0]);  // prints 9500
        System.out.println("Third day:      " + daysOfWeek[2]);  // prints Wednesday

        // .length gives you the number of slots (NOT a method call — no parentheses!)
        System.out.println("Number of days: " + daysOfWeek.length); // prints 5
    }
}
Watch Out: .length has no parentheses
Arrays expose their size through a property called length, not a method. Write daysOfWeek.length — NOT daysOfWeek.length(). Adding parentheses causes a compile error because length is a field, not a method. Strings, by contrast, use length() WITH parentheses. Yes, it's inconsistent. Welcome to Java.
Production Insight
Array declaration without new is just a reference — int[] scores; allocates zero memory. Trying to use it throws NullPointerException.
Array creation with new int[5] allocates 20 bytes (5 ints * 4 bytes) and zero-initialises all slots. This is eager allocation, not lazy.
Rule: For large arrays, consider memory usage: int[1_000_000] allocates 4MB immediately. Validate array size from external input before allocating.
Key Takeaway
Arrays are zero-indexed — the first element is always at index 0 and the last is at index array.length - 1. Writing array[array.length] always causes an ArrayIndexOutOfBoundsException.
An array's size is fixed at creation time and cannot change. If you need a resizable collection, reach for ArrayList instead.
Rule: Always use array.length to get size, not a hardcoded number. For loops, condition is i < array.length.
Java Arrays: Safe Looping & Common Pitfalls THECODEFORGE.IO Java Arrays: Safe Looping & Common Pitfalls From array creation to safe traversal and method handling Array Creation Fixed-size container for elements Loop with < length Use < not <= to avoid bounds 2D Array Traversal Nested loops with .length checks Pass Array to Method Reference passed; changes persist Return Array Safely Return copy or unmodifiable view ⚠ Using <= in loop condition causes IndexOutOfBoundsException Always use < array.length for safe iteration THECODEFORGE.IO
thecodeforge.io
Java Arrays: Safe Looping & Common Pitfalls
Arrays Java

Looping Through Arrays — The Right Way to Visit Every Slot

Creating an array is only half the job. The real power comes from being able to do something with every element automatically, without writing repetitive code. That's what loops are for. There are two main approaches in Java, and knowing when to use each one is a sign of a developer who actually understands the tool.

The classic for loop gives you the index at every step. Use this when you need to know the position of each element — for example, when printing 'Rank 1:', 'Rank 2:', etc., or when you need to compare neighbouring elements. The downside is a little more ceremony: you manage a counter variable yourself.

The enhanced for loop (also called the 'for-each' loop) is cleaner. It hands you each value directly, one at a time, without exposing the index. Use this when you simply want to read or process every element and you don't care which position it's in. It's shorter, harder to get wrong, and reads like plain English: 'for each temperature in weeklyTemperatures, do this'.

io/thecodeforge/java/arrays/ArrayIteration.javaJAVA
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package io.thecodeforge.java.arrays;

public class ArrayIteration {
    public static void main(String[] args) {

        double[] weeklyTemperatures = {18.5, 21.0, 19.3, 23.7, 22.1, 17.8, 20.4};

        // --- CLASSIC for LOOP ---
        // Use when you need the INDEX (position) of each element.
        // i starts at 0 (first slot), runs while i < length (NOT <=), steps by 1.
        System.out.println("=== Daily Forecast ===");
        for (int i = 0; i < weeklyTemperatures.length; i++) {
            // i is the current index; weeklyTemperatures[i] is the value at that index
            System.out.println("Day " + (i + 1) + ": " + weeklyTemperatures[i] + "°C");
        }

        // --- ENHANCED for-each LOOP ---
        // Use when you just want EVERY VALUE and don't need to track position.
        // Reads as: "for each temperature in weeklyTemperatures"
        double total = 0;
        for (double temperature : weeklyTemperatures) {
            total += temperature;  // add each value to the running total
        }

        // Calculate and display the weekly average
        double average = total / weeklyTemperatures.length;
        System.out.printf("%nWeekly average: %.1f°C%n", average);
    }
}
Pro Tip: Default to for-each, reach for classic for only when you need the index
Using a classic for loop when you don't actually need i is a subtle code smell — it adds noise and creates an extra variable that could accidentally be misused. The for-each loop signals clearly to anyone reading your code: 'I just need every value, nothing fancy.' Only pull out the index-based loop when the position genuinely matters.
Production Insight
The for-each loop prevents off-by-one errors entirely — you never write an index. Use it for reading.
But for-each gives you a copy of primitive values, not a reference. You cannot modify the array using for-each.
Rule: Use classic for loop when you need to modify array elements. Use for-each when you only read them.
Key Takeaway
Use the classic for loop when you need the index; use the enhanced for-each loop when you only need the values — it's shorter, safer, and more readable.
For-each cannot modify array elements (the loop variable is a copy). Use indexed loop for writes.
Rule: If your loop condition is i <= array.length, it's almost certainly wrong. Use <.

Arrays of Arrays — A Quick Look at 2D Arrays

Sometimes one row of data isn't enough. Think of a seating chart for a cinema: you have rows AND seats within each row. Or a spreadsheet: rows and columns. Java handles this with a two-dimensional array — essentially an array whose elements are themselves arrays. Picture the egg carton analogy again, but now imagine a whole box of egg cartons stacked on top of each other. You need two numbers to pinpoint one egg: which carton (row), and which slot within that carton (column).

You declare a 2D array with two sets of square brackets: int[][]. The first index selects the row; the second selects the column within that row. Everything else you already know still applies — zero-based indexing, .length for size, loops for iteration.

2D arrays are genuinely useful: game boards, image pixels (rows and columns of colour values), timetables, and matrix maths all map naturally onto them. You won't need them on day one, but recognising the pattern now means they won't feel foreign when they appear.

io/thecodeforge/java/arrays/CinemaSeatingChart.javaJAVA
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
package io.thecodeforge.java.arrays;

public class CinemaSeatingChart {
    public static void main(String[] args) {

        // A cinema with 3 rows, each containing 4 seats.
        // true = seat is booked, false = seat is available.
        // Outer array = rows (3 rows), inner arrays = seats per row (4 each).
        boolean[][] seatBooked = {
            {true,  true,  false, true },   // Row 0 (front)
            {false, false, false, false},   // Row 1 (middle) — all free
            {true,  false, true,  true }    // Row 2 (back)
        };

        System.out.println("=== Cinema Seat Availability ===");
        System.out.println("(O = Available,  X = Booked)\n");

        // Outer loop walks through each ROW
        for (int row = 0; row < seatBooked.length; row++) {
            System.out.print("Row " + (row + 1) + ":  ");

            // Inner loop walks through each SEAT in the current row
            for (int seat = 0; seat < seatBooked[row].length; seat++) {
                // Ternary operator: if booked print X, otherwise print O
                System.out.print(seatBooked[row][seat] ? " X " : " O ");
            }
            System.out.println(); // move to next line after each row
        }

        // Count total available seats using for-each loops
        int availableSeats = 0;
        for (boolean[] row : seatBooked) {          // each row
            for (boolean seat : row) {              // each seat in that row
                if (!seat) availableSeats++;        // if NOT booked, count it
            }
        }
        System.out.println("\nAvailable seats: " + availableSeats);
    }
}
Interview Gold: Java's 2D arrays are 'jagged' by design
In Java, a 2D array is literally an array of arrays — and each inner array can have a different length. seatBooked[0].length could be 4 while seatBooked[1].length is 6. This is called a jagged array. Many interviewers ask about this to see if you understand the underlying structure. Languages like C store true rectangular matrices in memory; Java doesn't — each row is a separate object.
Production Insight
2D array memory layout is not contiguous in Java. Each row is a separate array object on the heap.
The outer array stores references to the row arrays. This means int[1000][1000] allocates 1001 objects: one outer + 1000 rows.
Rule: For large matrices, consider using a 1D array with manual index calculation: int size = rows cols; int[] matrix = new int[size]; Access: value = matrix[row cols + col]. This is one object, faster iteration, better cache locality.
Key Takeaway
Java 2D arrays are arrays of arrays — each row is a separate object, potentially different lengths (jagged).
Use grid[row].length for inner loop bounds, not grid[0].length (fails on jagged arrays).
Rule: For rectangular matrices, a 1D array with manual index calculation is more memory-efficient and cache-friendly.

Passing Arrays to Methods — Why Your Method Just Got a Reference, Not a Copy

Arrays are objects. When you pass an array to a method, you pass a reference to the original array. The method can change the contents. This catches juniors off guard in production. If you want to protect your array from unintended modifications, pass a clone or use System.arraycopy for a shallow copy. For primitive arrays, clone works fine. For object arrays, you need a deep copy if the objects are mutable. The point is: understand that you're sharing the same memory. If you don't want that, make a defensive copy before handing it over. This is why we see bugs like logging services mutating input arrays. Always document whether a method modifies its array parameter.

PassingArrays.javaJAVA
1
2
3
4
5
6
7
8
9
10
11
12
13
// io.thecodeforge
public class PassingArrays {
    public static void main(String[] args) {
        int[] scores = {95, 87, 73};
        System.out.println("Before: " + java.util.Arrays.toString(scores));
        modifyArray(scores);
        System.out.println("After: " + java.util.Arrays.toString(scores));
    }

    static void modifyArray(int[] arr) {
        arr[0] = 99; // changes original array!
    }
}
Output
Before: [95, 87, 73]
After: [99, 87, 73]
Production Trap:
Never pass internal arrays directly to third-party code unless you expect mutation. Clone first with array.clone() or Arrays.copyOf().
Key Takeaway
Arrays are references. Pass a clone if you need to protect the original.

Returning an Array from a Method — Don't Expose Internal State

When you return an array from a method, you are returning a reference to the same array. If that array is an internal field of your class, callers can modify your class's state. This is a design flaw. In Spring Boot services, we often return data transfer objects (DTOs), but if you're returning an array directly from a repository or a service, make a copy. The caller gets what they need; your internal state stays safe. Use Arrays.copyOf or System.arraycopy for primitives. For objects, consider returning an unmodifiable list or a defensive copy. This avoids Heisenbugs where a caller mutates the array and breaks other parts of your service. The rule is simple: never return the same reference to your internal array.

ReturningArrays.javaJAVA
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// io.thecodeforge
public class ReturningArrays {
    private int[] internalData = {10, 20, 30};

    public int[] getDataUnsafe() {
        return internalData; // caller can mutate!
    }

    public int[] getDataSafe() {
        return java.util.Arrays.copyOf(internalData, internalData.length);
    }

    public static void main(String[] args) {
        ReturningArrays obj = new ReturningArrays();
        int[] bad = obj.getDataUnsafe();
        bad[0] = 999;
        System.out.println(obj.internalData[0]); // prints 999 — bug!
    }
}
Output
999
Production Trap:
Returning internal arrays from getters directly exposes your object's mutable state. Always use Arrays.copyOf() or Collections.unmodifiableList().
Key Takeaway
Return copies, not references, to keep your objects safe.

The Arrays Utility Class — Stop Writing Boilerplate, Use These Static Methods

Java's java.util.Arrays class is your best friend. It provides static methods for sorting, searching, comparing, filling, and converting arrays. In production, you'll use Arrays.toString() for debugging, Arrays.sort() for quick ordering, Arrays.binarySearch() for fast lookups on sorted arrays, and Arrays.equals() for comparing contents. For copying, use Arrays.copyOf() or Arrays.copyOfRange(). These are optimized and handle edge cases better than manual loops. For example, Arrays.fill() initializes all elements to a default value in one line. Do not write your own sort. Do not loop to print an array. Use the utility class. It's been battle-tested since Java 1.2 and is a core part of the Spring Boot ecosystem.

ArraysUtility.javaJAVA
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// io.thecodeforge
import java.util.Arrays;

public class ArraysUtility {
    public static void main(String[] args) {
        int[] numbers = {5, 3, 8, 1, 2};

        // Print
        System.out.println("Original: " + Arrays.toString(numbers));

        // Sort
        Arrays.sort(numbers);
        System.out.println("Sorted: " + Arrays.toString(numbers));

        // Search (binarySearch requires sorted array)
        int index = Arrays.binarySearch(numbers, 3);
        System.out.println("Index of 3: " + index);

        // Fill
        Arrays.fill(numbers, 0);
        System.out.println("Filled: " + Arrays.toString(numbers));

        // Compare
        int[] other = {0, 0, 0, 0, 0};
        System.out.println("Equals: " + Arrays.equals(numbers, other));
    }
}
Output
Original: [5, 3, 8, 1, 2]
Sorted: [1, 2, 3, 5, 8]
Index of 3: 2
Filled: [0, 0, 0, 0, 0]
Equals: true
Production Trap:
Don't use Arrays.asList() with primitive arrays directly — it wraps the array as a list, not the elements. Use Arrays.stream().boxed().collect(Collectors.toList()) instead.
Key Takeaway
Use java.util.Arrays for common operations. Don't reinvent sorting or copying.
● Production incidentPOST-MORTEMseverity: high

The Off-by-One That Corrupted 2.4 Million Customer Records

Symptom
The batch job ran for 2.4 million records, showing 100% progress. Then it crashed with ArrayIndexOutOfBoundsException. The error handler caught the exception and rolled back the entire transaction. All 2.4 million processed records were lost. The job had to be re-run from scratch, costing 8 hours of processing time.
Assumption
The developer assumed i <= array.length was correct because 'i should go up to the length'. They didn't realise the last valid index is length - 1. The loop condition should be i < array.length. The dev environment had 10 customers, and the exception was caught by the test harness, so the team never saw the rollback in testing.
Root cause
The loop condition was for (int i = 0; i <= customers.length; i++). For an array of length 2.4 million, the loop iterates i = 0 to 2,400,000. The last iteration tries to access customers[2400000], which does not exist (valid indexes are 0 to 2,399,999). The exception occurred after processing the 2.4 millionth record, so all preceding records were already processed but not yet committed. The error handler caught the exception and called transaction.rollback(), discarding all work. One character (<= vs <) caused 8 hours of reprocessing.
Fix
1. Changed the loop condition to for (int i = 0; i < customers.length; i++). 2. Added unit test that verifies the loop never accesses index == length. 3. For production batch jobs, use atomic commit after each batch of 1000 records, not a single transaction for the entire job. This limits rollback scope. 4. Added assertion at loop start: assert i < customers.length : 'Index out of bounds at ' + i; in debug builds. 5. Enabled -ea (enable assertions) in CI to catch off-by-one errors before production.
Key lesson
  • The boundary between 'works' and 'crashes' in array code is a single character: < vs <=. Always use i < array.length.
  • A failing transaction that rolls back after processing all records is devastating for batch jobs. Commit periodically, not just at the end.
  • ArrayIndexOutOfBoundsException is a runtime exception. The code compiles fine. The bug only appears when the last iteration runs.
  • Always test loops with the smallest possible array (size 1) to verify boundary conditions. A 1-element array crashes immediately if you use <=.
Production debug guideSymptom → Action mapping for common array failures in production Java applications.5 entries
Symptom · 01
ArrayIndexOutOfBoundsException in logs — index equals array length
Fix
Loop condition uses <= instead of <. Check all for loops: for (int i = 0; i <= arr.length; i++) is always wrong. Fix to <. Also check manual index calculations: int lastIndex = arr.length; arr[lastIndex] = value; — last index should be arr.length - 1.
Symptom · 02
ArrayIndexOutOfBoundsException with negative index
Fix
Index calculation went negative. Check index - 1 when index is 0, or binarySearch result that's negative and used directly. Validate index before access: if (idx >= 0 && idx < arr.length) { ... }
Symptom · 03
Array values are zero or null unexpectedly
Fix
Array was declared but not initialized. For local arrays, default values are 0 for numeric, false for boolean, null for objects. If you expected specific values, you forgot to assign them. Add initialization: int[] arr = new int[]{1,2,3}; or loop to fill.
Symptom · 04
Printing array shows [I@6d06d69c instead of values
Fix
You printed the array variable directly. Use Arrays.toString(arr) for 1D arrays, Arrays.deepToString(arr) for 2D arrays. Add import java.util.Arrays; at top.
Symptom · 05
NullPointerException when accessing array element
Fix
The array reference is null. Check if you called new int[size]. Declaration alone (int[] arr;) does not create the array. Add arr = new int[10]; before access.
★ Java Array Debug Cheat SheetFast diagnostics for array issues in production Java applications.
ArrayIndexOutOfBoundsException in logs
Immediate action
Find the loop condition — likely uses <= instead of <
Commands
grep -n 'for.*<=' src/**/*.java
grep -n 'for.*>=' src/**/*.java
Fix now
Change i <= arr.length to i < arr.length. For reverse loops, i >= 0 is correct for the lower bound.
Printing array shows [I@6d06d69c+
Immediate action
Find System.out.println that prints array directly
Commands
grep -n 'System.out.println.*\[\]' src/**/*.java
grep -n 'System.out.println.*[a-z]\[' src/**/*.java
Fix now
Replace System.out.println(arr) with System.out.println(Arrays.toString(arr)). Add import java.util.Arrays;
Array contains zeros but should have values+
Immediate action
Check if array was initialized after declaration
Commands
grep -n 'new int\[.*\]' src/**/*.java | grep -v '= {\|Arrays.fill'
grep -n 'int\[\].*=.*new' src/**/*.java
Fix now
Either initialize at declaration: int[] arr = {1,2,3}; or fill in loop: for (int i = 0; i < arr.length; i++) arr[i] = i;
NullPointerException when accessing array+
Immediate action
Check if array was created with new
Commands
grep -n 'int\[\]\s\+\w\+\s*;' src/**/*.java | grep -v '='
grep -n 'arr\[' src/**/*.java | grep -v 'new int\['
Fix now
Ensure int[] arr = new int[10]; not just int[] arr;. For field arrays, initialize in constructor or declaration.
2D array has ArrayIndexOutOfBoundsException on row+
Immediate action
Check inner loop uses `grid[row].length`, not `grid[0].length`
Commands
grep -n 'grid\[0\]\.length' src/**/*.java
grep -A5 'for.*int.*row' src/**/*.java | grep 'grid\['
Fix now
Inner loop: for (int col = 0; col < grid[row].length; col++). Each row may have different length (jagged array).
Java Array Loops Compared
FeatureClassic for LoopEnhanced for-each Loop
Access to indexYes — you control the counter variable iNo — index is hidden from you
Syntax complexityMore verbose — init, condition, incrementMinimal — just 'for (type var : array)'
Risk of off-by-one errorHigher — easy to write i <= length by mistakeNone — Java handles boundaries automatically
Can modify array elementsYes — use index to write back: array[i] = newValNo — modifying the loop variable doesn't change the array
Best used whenYou need position, reverse traversal, or skipping elementsYou just want to read or process every element in order
ReadabilityLower for simple reads — more noiseHigher — reads like natural language
PerformanceSame as for-each (compiler generates same bytecode for arrays)Same — no overhead difference

Key takeaways

1
Arrays are zero-indexed
the first element is always at index 0 and the last is at index array.length - 1. Writing array[array.length] always causes an ArrayIndexOutOfBoundsException.
2
An array's size is fixed at creation time and cannot change. If you need a resizable collection, reach for ArrayList instead.
3
Use the classic for loop when you need the index; use the enhanced for-each loop when you only need the values
it's shorter, safer, and more readable.
4
Never print an array with System.out.println() directly
you'll get a memory address. Always use Arrays.toString() for 1D arrays or Arrays.deepToString() for 2D arrays.
5
Array defaults
numeric → 0, boolean → false, object → null. Local array variables are initialized to these defaults, unlike local primitive variables which require explicit initialization.

Common mistakes to avoid

5 patterns
×

ArrayIndexOutOfBoundsException from using <= instead of <

Symptom
Program crashes at runtime with ArrayIndexOutOfBoundsException: Index 5 out of bounds for length 5. This happens because a 5-element array's last valid index is 4, not 5.
Fix
Always write i < array.length, never i <= array.length. Read it aloud: 'while i is less than the length' — the moment i equals the length, you've gone one step too far.
×

Printing an array with System.out.println() and getting garbage output

Symptom
Writing System.out.println(scores) expecting to see [95, 87, 76] but instead seeing something like [I@6d06d69c. That cryptic string is the array's memory address, not its contents.
Fix
Use Arrays.toString(scores) for a 1D array, or Arrays.deepToString(grid) for a 2D array. Both are in java.util.Arrays — add import java.util.Arrays; at the top of your file.
×

Trying to resize an array after creation

Symptom
You create int[] basket = new int[3], fill it up, then try to add a fourth item and it simply won't fit — there's no basket.add() method because arrays don't have one.
Fix
If your collection needs to grow or shrink dynamically, use an ArrayList<Integer> instead. Arrays are the right choice when the size is known and fixed; ArrayList is the right choice when it isn't.
×

Treating array names as values that can be reassigned to change size

Symptom
int[] arr = new int[3]; arr = new int[5]; — This works, but it creates a new array, abandoning the old one. The original 3 elements are lost.
Fix
This reassigns the reference, not resizes. For resizing, you must copy elements manually using System.arraycopy() or Arrays.copyOf(). Better to use ArrayList.
×

Accessing array elements before initialization

Symptom
int[] arr; arr[0] = 5; throws NullPointerException. The array reference is null because no array was created.
Fix
Always create the array: int[] arr = new int[10]; before accessing elements. Declaration alone does not allocate memory.
INTERVIEW PREP · PRACTICE MODE

Interview Questions on This Topic

Q01SENIOR
What is the difference between an array and an ArrayList in Java, and wh...
Q02JUNIOR
If I declare `int[] numbers = new int[10]`, what value does `numbers[5]`...
Q03SENIOR
How would you find the second-largest value in an integer array without ...
Q04JUNIOR
What is the time complexity of accessing an array element by index in Ja...
Q01 of 04SENIOR

What is the difference between an array and an ArrayList in Java, and when would you choose one over the other?

ANSWER
An array has a fixed size set at creation and cannot change. ArrayList is a resizable wrapper (backed by an array) that grows automatically when capacity is exceeded. Choose an array when: (1) the size is known and fixed (e.g., days of week, RGB channels), (2) performance is critical (primitive arrays avoid boxing overhead), (3) you need a multi-dimensional fixed-size grid. Choose ArrayList when: (1) the size is unknown or changes over time, (2) you need convenient methods like add(), remove(), contains(), (3) you're working with generics or APIs that expect Collection. ArrayList's growth factor is 1.5x (doubling in older versions), which causes occasional O(n) copy operations. Arrays are slightly faster for iteration and access due to no method call overhead, but for most use cases, ArrayList is the right default.
FAQ · 4 QUESTIONS

Frequently Asked Questions

01
What is the default value of an array element in Java?
02
Can a Java array hold different data types at the same time?
03
What is the difference between `int[] numbers` and `int numbers[]` in Java?
04
How do I resize an array in Java?
N
Naren Founder & Principal Engineer

20+ years shipping production Java in banking & fintech. Written from production experience, not tutorials.

Follow
Verified
production tested
May 24, 2026
last updated
1,554
articles · all by Naren
🔥

That's Arrays. Mark it forged?

4 min read · try the examples if you haven't

Previous
Labeled break and continue in Java
1 / 8 · Arrays
Next
Multi-dimensional Arrays in Java