Arrays and Their Trade-offs

beginner25 min

Starting from arrays

You have already used arrays to store values. This lesson looks at them differently — not as syntax to memorise, but as one option among several, with specific strengths and specific limits.

Every other structure in this module exists because arrays fall short in some particular way. Understanding exactly where they fall short is what makes the rest make sense.

If you need a refresher on the syntax first, see Arrays in Java Basics.

What an array actually is

An array is a single block of memory holding elements of the same type, laid out end to end.

int[] readings = new int[5];
readings[0] = 120;
readings[1] = 118;

Because the elements sit next to each other and every element is the same size, the computer can jump straight to any position with arithmetic. To find readings[3], it starts at the beginning of the block and skips forward three elements’ worth of space.

That is why reading or writing any element takes the same amount of time regardless of position. Element 0 and element 999 cost the same.

What arrays are good at

  • Reading any element by index — instant, no searching
  • Writing to any element by index — instant
  • Memory efficiency — no overhead beyond the values themselves
  • Predictable performance — no hidden resizing or reallocation

The limitation that matters

An array’s length is fixed when you create it. You cannot grow it.

int[] readings = new int[5];
// readings can hold exactly 5 values. Not 6.

If you need a sixth value, you have to create a bigger array and copy everything across:

int[] bigger = new int[10];
System.arraycopy(readings, 0, bigger, 0, readings.length);
readings = bigger;

That copy touches every element, so it costs time proportional to the size. Doing it once is fine. Doing it every time you add a value is slow, and it is the reason ArrayLists exist.

Inserting and removing

Arrays have a second limitation. Suppose you want to remove the element at index 1 and close the gap:

int[] values = {10, 20, 30, 40, 50};

// remove index 1 by shifting everything after it left
for (int i = 1; i < values.length - 1; i++) {
    values[i] = values[i + 1];
}
// values is now {10, 30, 40, 50, 50} — the last slot is stale

Every element after the removal point has to move. Inserting in the middle is the same problem in reverse. For a large array this is expensive, and there is no way around it — the elements are packed together, so making room means moving things.

Array operation costs

OperationCostWhy
Read a[i]InstantDirect jump by arithmetic
Write a[i]InstantDirect jump by arithmetic
Find a valueProportional to lengthMust check each element
Insert in the middleProportional to lengthMust shift elements right
Remove from the middleProportional to lengthMust shift elements left
Add beyond capacityProportional to lengthMust allocate and copy

Working with a partly-filled array

A common pattern when you know the maximum size but not the actual count: allocate for the maximum and track how many slots are in use.

int[] readings = new int[100];
int count = 0;

void addReading(int value) {
    if (count < readings.length) {
        readings[count] = value;
        count++;
    }
}

int average() {
    if (count == 0) return 0;
    int total = 0;
    for (int i = 0; i < count; i++) {   // loop to count, not readings.length
        total += readings[i];
    }
    return total / count;
}

The important detail is looping to count rather than readings.length. The unused slots still hold zeros, and including them would drag the average down.

This pattern appears constantly in robot code, where you might buffer a fixed number of sensor readings.

Common array mistakes

  • Off-by-one at the end. Valid indices run from 0 to length - 1. Using <= in a loop condition throws ArrayIndexOutOfBoundsException.
  • Confusing length with count. A partly-filled array’s length is its capacity, not how much you have stored.
  • Assuming a copy is a copy. int[] b = a; makes both names refer to the same array. Changing b[0] changes a[0]. Use a.clone() or Arrays.copyOf(a, a.length) for a real copy. See Objects and References.
  • Forgetting arrays of objects start as null. new String[5] holds five nulls, not five empty strings.

Two-dimensional arrays

An array whose elements are themselves arrays. Useful for grids, matrices, and tables.

int[][] grid = new int[3][4];      // 3 rows, 4 columns
grid[1][2] = 7;                     // row 1, column 2

for (int r = 0; r < grid.length; r++) {
    for (int c = 0; c < grid[r].length; c++) {
        System.out.print(grid[r][c] + " ");
    }
    System.out.println();
}

grid.length is the number of rows; grid[r].length is the length of that row. Reading them in the wrong order is a frequent bug on non-square grids.

Choosing an array

Use an array when all of the following hold:

Arrays are the right choice when

  • You know the size in advance, or a safe maximum
  • You mostly read and write by index
  • You rarely insert or remove from the middle
  • You care about memory or predictable speed

If the size changes as the program runs, use an ArrayList. If you insert and remove at the ends constantly, look at Deques.

Practice

Write each of these using plain arrays only.

  1. Create an array of 10 integers, fill it with the numbers 1 through 10, and print the total.
  2. Write a method that takes an int[] and returns the largest value. Handle an empty array sensibly.
  3. Write a method that reverses an int[] in place, without creating a second array.
  4. Write a method that takes an int[] and a value, and returns a new array with that value appended.
  5. Create a 3 × 3 grid of integers and print the sum of each row and each column.
Hints
  1. One loop to fill, one to total. Or do both in the same loop.
  2. Start your running maximum at arr[0], not 0 — otherwise negative-only arrays give the wrong answer. Decide what to return when the array has no elements.
  3. Swap the first with the last, second with second-to-last, and stop at the middle. Two index variables moving toward each other.
  4. Arrays.copyOf(arr, arr.length + 1) gives you a longer copy; put the new value in the last slot.
  5. Two passes, or one pass accumulating both sets of totals into two arrays.

Next

Review