Phase 0 · Foundations

Many values, one name

By the end you can keep five hundred values under one name, reach any of them instantly, and read the crash message Java gives you when you reach one slot too far.

⏱ ~30 minutes🧩 Needs: 0.4💻 Code: src/

Say your class of 30 people just sat a test, and you want the average mark. You already know how to make a box in memory and put a number in it. So you'd need thirty boxes: mark1, mark2, mark3… That's thirty lines of typing. Then one enormous adding-up line at the end. Now imagine the whole school. Nine hundred people. You are not going to type nine hundred names. Nobody is. So programmers do something else instead, and it's the trick this whole chapter is about.

What you'll be able to do

Section 1One name, many numbered slots

Here's the thirty-boxes problem in miniature. Five test scores, done the painful way, then done properly. Both halves of this program print the same total.

src/FiveScores.java
// The silly way: one name per value.
int score1 = 8;
int score2 = 5;
int score3 = 9;
int score4 = 7;
int score5 = 6;
int total = score1 + score2 + score3 + score4 + score5;

// The sensible way: one name, five numbered slots.
int[] scores = {8, 5, 9, 7, 6};
int sum = 0;
for (int i = 0; i < scores.length; i++) {
    sum = sum + scores[i];
}

Line by line. The first five lines make five separate boxes in memory, each with its own label, exactly as in chapter 0.2. Line six reaches into all five and adds them up. Fine for five. Hopeless for nine hundred.

Then the interesting half. int[] scores says "this name won't hold one whole number — it will hold a row of whole numbers". That pair of square brackets is the whole difference. {8, 5, 9, 7, 6} fills the row in, left to right. Next line makes a counter starting at nothing. Then the loop from 0.3 walks the row, adding each value onto sum. It doesn't matter whether the row holds 5 values or 5,000 — that loop is the same length either way.

That row of values has a name: an array. An array is one name that owns a fixed number of slots, and every slot is numbered.

Think of it like this

An array is a street. One name — Baker Street — and the houses on it have door numbers. You never say "Baker Street" and expect the postman to find a person. You say Baker Street, number 4. The name gets you to the street. The number gets you to the door. And once a street is built you can't squeeze an extra house in the middle. Arrays are the same: the number of slots is fixed the moment you make one.

Making an array when you don't have the values yet

Sometimes you know how many slots you want but not what goes in them. Maybe the marks haven't been typed in yet. For that there's a second way to make an array:

src/NewArray.java
int[] numbers = new int[3];
boolean[] flags = new boolean[3];
String[] names = new String[3];
double[] prices = new double[3];

System.out.println("numbers[0] = " + numbers[0]);
System.out.println("flags[0]   = " + flags[0]);
System.out.println("names[0]   = " + names[0]);
System.out.println("prices[0]  = " + prices[0]);

Each of the first four lines does the same job for a different kind of value. Read new int[3] out loud as "make me a new row with three int slots". new is Java's word for "build me one of these, right now, in memory". The number in brackets is how many slots, and it's locked in forever.

The four println lines then peek into slot 0 of each row. Nobody put anything in those slots. So what comes out?

Predict before you run

Four brand new arrays. Nothing has been stored in any of them. What do you think those four lines print — and why? Have a real guess. There's a genuine surprise in one of these four.

$ java NewArray
numbers[0] = 0
flags[0]   = false
names[0]   = null
prices[0]  = 0.0

Many people guess "an error" or "empty" or "blank". It's none of those. Java refuses to hand you a slot with rubbish in it. So it fills every slot the moment the array is built. Each type gets its own boring default. Whole numbers get 0. True-or-false values get false. Decimals get 0.0.

The odd one out is names[0], which prints null. null is Java's word for "this slot points at nothing at all". Not an empty value. The absence of one. It's not a mistake, and it's not a crash. But it is the single most famous source of crashes in Java. We'll meet it properly in Phase 1. For now: a fresh String[] is a row of nulls. Put something real in before you use it.

Going deeper Why Java bothers to fill the slots for you

Those defaults are not politeness. The Java Language Specification demands them, so every machine gives the same answer.

Some older languages hand you the memory exactly as it was left. Whatever the last program wrote there is what you read. Your program then behaves differently on Tuesday, and old data leaks out of it.

Java pays a small price to avoid that: it writes zeros across the whole block first. You never see uninitialised memory. That guarantee costs a little speed and buys you a program that behaves the same way twice.

Worth remembering

Section 2Counting starts at zero, and here's why

You've seen scores[0] a few times now and probably let it slide. Stop and look at it. This is where more beginners lose more hours than anywhere else in the language.

The first slot of an array is slot number 0. The second is 1. The third is 2. So an array with 5 slots has slots numbered 0, 1, 2, 3, 4. There is no slot 5. Read that again. An array of 5 has no slot 5.

Think of it like this

Picture a tape measure along the street, its zero end pinned to the first front door. A house number isn't "which house is it" — it's "how far along from the start". The first house is nought metres along. You're standing on it. So the number in the brackets is a distance from the beginning, not a position in a queue. Programmers call it the index.

That's not a random choice by Java's designers. It's the shape of the machine underneath. An array lives in memory as one unbroken run of boxes, all the same size, one after another. Java remembers where the run starts. To find slot i, it adds i box-widths to the start. Slot 0 needs no adding at all. Counting from 1 would mean subtracting 1 on every single access, forever, in every program on earth. So we count from 0.

Five slots, numbered 0 to 4

String[] days = {"Mon","Tue","Wed","Thu","Fri"}; — Java sets aside five slots side by side and fills them left to right.

days

0 Mon
1 Tue
2 Wed
3 Thu
4 Fri

days[0] — zero steps along from the start. That's Monday. The first item has index zero.

days

0 Mon
1 Tue
2 Wed
3 Thu
4 Fri

days.length is 5 — five slots exist. But the biggest index is 4, because we started at 0. That gap of one is the whole problem.

days

0 Mon
1 Tue
2 Wed
3 Thu
4 Fri

days[5] — one step past the end of the street. There is no house there. Java will not give you whatever happens to be sitting in memory next door. It stops the program instead. We'll do exactly that in a moment.

days

3 Thu
4 Fri
5 💥 nothing

So the last slot is always at index length - 1. Burn that phrase in. Here it is working:

src/Indexing.java
String[] days = {"Mon", "Tue", "Wed", "Thu", "Fri"};

System.out.println("length is " + days.length);
System.out.println("days[0] is " + days[0]);
System.out.println("days[1] is " + days[1]);
System.out.println("last slot number is " + (days.length - 1));
System.out.println("days[days.length - 1] is " + days[days.length - 1]);

Line one builds the five-slot array. The next three lines ask three easy questions: how many slots, what's in slot 0, what's in slot 1. Then the arithmetic out loud: 5 slots means 4 is the last index. The final line is the pattern worth stealing. Put that subtraction inside the brackets. Now you get the last item without knowing how long the array is.

$ java Indexing
length is 5
days[0] is Mon
days[1] is Tue
last slot number is 4
days[days.length - 1] is Fri

Why .length has no brackets

You have now typed days.length several times with no round brackets after it. That is worth one minute.

An array's size is a field — a fact stored on the thing itself. Think of a label stuck on the side of a box. You read a label. You don't run it.

Round brackets mean something specific in Java: "run this piece of work". That's what they meant on the methods you wrote in 0.4. No brackets means "read this stored fact". An array's size is decided the moment it is built and never moves, so there is nothing to work out. Java wrote the number down. You read it.

You have been writing String since 0.2, and text asks for its size a different way — with brackets. There is a real reason for that, and it belongs to chapter 0.6, where text gets opened up properly. For now, arrays: no brackets.

Going deeper Arrays aren't really objects with a field

Strictly, length is not an ordinary field you could have written yourself. Arrays are built into the language at a much lower level than that.

When javac compiles days.length, it emits a single machine instruction called arraylength. The size sits in the array's header in memory, and that one instruction reads it. There is no method call, no lookup by name.

So the reason it has no brackets is not tidiness. There is genuinely no method there to call. Phase 1 covers what objects and fields really are, and arrays will look like a special case even then. They are.

Now let's break something on purpose

Remember the promise from the stepper: reach past the end and Java stops the program. Let's do it from inside a method. Then we can read the trail it leaves behind — the same stack traces you met in 0.4.

src/Crash.java
public static void main(String[] args) {
    String[] days = {"Mon", "Tue", "Wed", "Thu", "Fri"};
    System.out.println("About to read slot 5...");
    printSlot(days, 5);
    System.out.println("You will never see this line.");
}

static void printSlot(String[] items, int slot) {
    System.out.println(items[slot]);
}

Five slots, numbered 0 to 4. We print a warning. Then we hand the array and the number 5 to a little method called printSlot. Its only job is to print whatever slot it was told to look at. Back in main there's one more println that we're betting never runs.

Predict before you run

Slot 5 of a five-slot array. Two questions: does the last line print, and if Java complains, what do you think it says? Guess the wording. Getting it half right is genuinely useful here — you'll remember the real text better for having tried.

$ java Crash
About to read slot 5...
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 5 out of bounds for length 5
	at Crash.printSlot(Crash.java:11)
	at Crash.main(Crash.java:6)

The warning printed. The last line didn't — the program died mid-flight, as promised. Now unpack that message, because Java is being unusually helpful.

ArrayIndexOutOfBoundsException is a long name for one short thing: an array index was outside the allowed range. "Bounds" means the edges. Then the best part: Index 5 out of bounds for length 5. That tells you the number you asked for. It also tells you how many slots there really were. When those two numbers match, you are off by exactly one. You almost certainly wrote <= where you wanted <, or forgot a - 1.

Then the two indented at lines from 0.4. Read them top down. The crash happened at line 11, inside printSlot. And printSlot was called from line 6, inside main. Top line is where it broke. The lines below are how it got there. The bad number was born on line 6, and the explosion happened on line 11. A stack trace hands you both.

Ten seconds that will save you an hour

Reading "it starts at zero" is not the same as believing it. Here are five slots. The page will ask for one by its index. You click the box you think it means. Get it wrong once and you'll never get it wrong again — which is the entire point.

 

Worth remembering

Section 3Visiting every slot

Arrays are only useful if you can walk them. There are two ways, and choosing between them is easy once you know the question to ask.

src/Loops.java
String[] pets = {"cat", "dog", "rat"};

for (int i = 0; i < pets.length; i++) {
    System.out.println(i + ": " + pets[i]);
}

for (String pet : pets) {
    System.out.println(pet);
}

The first loop is the counting one from 0.3. It starts i at 0, keeps going while i is less than the length, and adds one each time round. For a 3-slot array that gives 0, 1, 2 and then stops — exactly slots 0 to 2, no overshoot. i < pets.length is the safe form. Write it that way every time and the crash above can never happen.

The second loop is new. Read the colon as the word "in": for each String called pet in pets. It's the for-each loop, and it hands you the values one at a time. No i, no length, no brackets — so no way to fall off the end. It cannot produce an out-of-bounds crash. That's not a small thing.

$ java Loops
-- counting for loop --
0: cat
1: dog
2: rat
-- for-each loop --
cat
dog
rat

Both loops printed the same three pets. Only the first one could print the numbers next to them.

So which one? One question decides it: do I need to know the slot number? Printing a numbered list needs i. So does comparing a slot with the one before it. So does writing values into the array. Use the counting loop for all three. Only looking at each value in turn? Use for-each.

Watch out

A for-each loop can't change the array. Writing pet = "hamster" inside it changes only the little copy called pet. The array is untouched. To store something in a slot you need pets[i] = "hamster", and for that you need the counting loop.

A grid is an array of arrays

A street of houses is one line. What if you want a chess board? Put an array in every slot of another array, so each slot holds a whole row.

src/Grid.java
String[][] board = {
    {"X", "O", "X"},
    {"O", "X", "O"},
    {"X", "O", "X"}
};

System.out.println("board[0][2] is " + board[0][2]);
System.out.println("rows: " + board.length);
System.out.println("columns in row 0: " + board[0].length);

for (int row = 0; row < board.length; row++) {
    for (int col = 0; col < board[row].length; col++) {
        System.out.print(board[row][col]);
    }
    System.out.println();
}

String[][] — two pairs of brackets — means "a row of rows". The three inner {…} groups are the three rows. board[0][2] reads as "row 0, then item 2 of that row". board.length is the number of rows. board[0].length is the length of row 0, so the number of columns.

Then two loops, one inside the other. The outer picks a row. The inner walks across it, printing each cell with print. Unlike println, print doesn't move to a new line. The empty System.out.println() ends each row's line.

Predict before you run

Three things, and take them one at a time. What does board[0][2] print? How many rows does it report? And the shape at the end — one long line of nine letters, or three lines of three? Experienced programmers reverse row and column here all the time, so write your answer down before you look.

$ java Grid
board[0][2] is X
rows: 3
columns in row 0: 3
XOX
OXO
XOX

Take the order first. board[0] picks the whole top row, which is {"X", "O", "X"}. Then [2] picks item 2 of that row — the third one across, because we count from 0. So: top row, third column, X. Row always comes first.

Now the honest bit. This board reads the same across as it does down. So swapping the two numbers also lands on an X. The letter can't prove you had the order right. Your reasoning can. There's a task below that breaks the symmetry so you can really check.

The shape is the interesting one. print never starts a new line, so all nine letters would land in a row — XOXOXOXOX. The only thing splitting them into three lines is that bare System.out.println() after the inner loop. Delete it and the grid collapses. One line of code is holding the picture together.

Worth remembering
Your turn

All in 05-arrays/src/. Compile with javac Name.java, run with java Name — no .java on the run.

Section 4Check yourself

You need to print the line slot 3 holds dog. Which loop do you reach for, and why?

A colleague's program crashes with Index 12 out of bounds for length 12. Without seeing their code, what's your best first guess?

Section 5What broke, and what surprised you

Open a plain text file and note anything from this chapter where your prediction and reality parted ways. Especially:

Those aren't trivia. Every one of them is a mistake that will cost you real time later. And you now have the three moves that arrays are made of. Build a row of slots. Reach into any one by its number. Walk all of them with the loop that fits.

Next chapter takes the same idea somewhere strange. Text turns out to be a row of numbered slots too. And it behaves in a way that catches almost everybody.

Nice. Chapter marked complete.