Arrays, one dimension
Storing many values under one name, indexing from zero, and walking an array with a loop.
Finished reading?
Mark this session so you can track where you are.
Storing many values under one name, indexing from zero, and walking an array with a loop.
Finished reading?
Mark this session so you can track where you are.
You can already store one number in a variable, and you can repeat work with a loop. But what happens when you have not one number to keep, but fifty? Naming fifty variables by hand is the problem this session solves. An array is a single name that holds many values in a row.
new int[n].0..length and walk an entire array with a for loop.a[a.length] is always one step too far.Picture a class of five students and you want to store each test score. With the tools you have so far, you reach for one variable per score.
public class Main { public static void main(String[] args) { int score0 = 10; int score1 = 20; int score2 = 30; int score3 = 40; int score4 = 50; System.out.println("The third score is " + score2); }}The third score is 30
It runs, and it is fine for five. Now the class grows to fifty. You would type fifty lines, each with a number stuck on the end of the name. Worse, suppose you wanted to print every score. You cannot loop, because a loop counter is just an int, and there is no way to say “the variable whose name ends in this number”. The names score0 through score4 look like a sequence to you, but to Java they are five unrelated variables that happen to share a prefix.
Loose numbered variables do not scale. You cannot count over them with a loop, and the count of them is frozen into your source code. We need one name that holds many values and lets a number pick which one.
balance1, balance2, balance3, this is the same complaint in a new shape. Data that belongs together is smeared across loose variables. An array is the first tool that fixes it: many values of the same type, gathered under one name.An array is a fixed-length row of slots, all of the same type, sitting under a single name. There are two common ways to make one.
When you know the values up front, write them in curly braces. The type before the name has square brackets, int[], which reads as “array of int”. Java counts the values for you, so this array has exactly three slots.
public class Main { public static void main(String[] args) { int[] scores = {10, 20, 30}; System.out.println("First slot: " + scores[0]); }}First slot: 10
When you do not yet have the values, but you know how many you need, ask for that many empty slots with new int[n]. Here new int[5] hands you five slots. They are not random junk: Java fills a fresh number array with zeros. You then fill them in later.
public class Main { public static void main(String[] args) { int[] scores = new int[5]; scores[0] = 10; scores[2] = 30; System.out.println("Slot 0 is " + scores[0]); System.out.println("Slot 1 is " + scores[1]); System.out.println("Slot 2 is " + scores[2]); }}Slot 0 is 10 Slot 1 is 0 Slot 2 is 30
Step through that and watch the array appear with five zeros, then watch slots 0 and 2 change while slot 1 stays at its default of zero. We never touched slot 1, so its starting value of 0 is exactly what prints.
a[i] = ....Each slot has a position, called its index. You reach a slot by writing the array name, then the index in square brackets: scores[0] is the first slot. The single most important fact about arrays, and the one that trips up every beginner once, is that counting starts at zero, not one.
So an array of three values has indices 0, 1, and 2. The first is at 0, and the last is at 2, which is one less than the count of three. Read it as an offset: scores[0]means “zero steps from the start”, which is the start itself.
Every array carries its own size, which you read with .length. Note carefully: it is a plain field, scores.length, with no parentheses. This is a real difference from text. A String uses name.length() with parentheses, because there it is a method call. An array uses scores.length with none. Mixing them up is one of the most common early typos.
3, scores.length is 3, but the valid indices are 0, 1, 2. The last valid index is scores.length - 1. Asking for scores[scores.length] always reaches one slot past the end and crashes. We will see that crash on purpose in a moment.Here is where arrays and loops click together. A for loop can count from 0 up to length - 1, and at each step you use the counter as the index. One small loop now handles an array of three or three thousand without a single extra line. Run this and watch the index pointer move along the row, lighting up one cell at a time.
public class Main { public static void main(String[] args) { int[] scores = {10, 20, 30}; for (int i = 0; i < scores.length; i = i + 1) { System.out.println("scores[" + i + "] = " + scores[i]); } System.out.println("There are " + scores.length + " scores"); }}scores[0] = 10 scores[1] = 20 scores[2] = 30 There are 3 scores
Read the loop condition slowly, because it is the heart of the whole pattern. We start i at 0, the first index. We keep going while i < scores.length, that is, while i is still 0, 1, or 2. The instant i reaches 3, the condition 3 < 3 is false and the loop stops, one step before trouble. Using < with length is the safe pattern. It visits every slot and never the phantom one past the end.
The canonical array walk is
for (int i = 0; i < a.length; i = i + 1). Start at zero, stop strictly below the length. Memorize the shape; you will write it thousands of times.
Printing is nice, but the point of holding many values together is to compute over them. Here is the classic move: scan the array and remember the biggest number you have seen. We start by assuming the first slot is the winner, then we check the rest. Anyone bigger takes the crown.
public class Main { public static void main(String[] args) { int[] temps = {62, 71, 55, 80, 68}; int max = temps[0]; for (int i = 1; i < temps.length; i = i + 1) { if (temps[i] > max) { max = temps[i]; } } System.out.println("The highest temperature is " + max); }}The highest temperature is 80
Two details earn their keep. First, max starts as temps[0], not as 0. If you started at 0 and every value were negative, your answer would wrongly be 0, a number not even in the array. Seeding from the first real value avoids that trap. Second, the loop starts at i = 1, not 0, because slot 0 is already the current champion, so there is nothing to gain by comparing it with itself. Stepping through: max begins at 62, rises to 71, holds through 55, rises to 80, and holds through 68. The final answer is 80.
Often you want to visit every element but you do not actually care about its index, only its value. Java has a shorter loop for exactly this, the for-eachloop. You read it as “for each value in the array, do this”.
public class Main { public static void main(String[] args) { int[] ages = {12, 4, 5}; for (int age : ages) { System.out.println(age); } }}12 4 5
The shape is for (int age : ages). On each pass, age holds the next value from the array, in order, with no index variable to manage at all. Compare it with the counting loop: the for-each is cleaner when you only need the values, while the counting for is what you reach for when you need the position too (for example, to write into a slot, or to compare neighbours).
The other everyday task is reducing a whole array to a single number, like a total or an average. The pattern is the same running-total idea from loops: keep an accumulator outside the loop and add each element into it.
public class Main { public static void main(String[] args) { int[] numbers = {2, 9, 0, 5, 12}; int sum = 0; for (int i = 0; i < numbers.length; i = i + 1) { sum = sum + numbers[i]; } double average = (double) sum / numbers.length; System.out.println("Sum = " + sum); System.out.println("Average = " + average); }}Sum = 28 Average = 5.6
The sum builds up to 28. The average line has one subtlety worth pausing on: we cast sum to double before dividing, so we get a real decimal average rather than an integer-division result. Without the (double), 28 / 5 would be the whole number 5, quietly dropping the fraction. This is the integer-division trap from operators and casting showing up in real code.
Sorting is the classic array workout, and the gentlest method to understand is bubble sort. The idea: walk the array comparing each pair of neighbours, and whenever the left one is bigger, swap them. After one full pass the largest value has “bubbled” to the end. Repeat enough passes and the whole array is sorted.
public class Main { public static void main(String[] args) { int[] arr = {7, 2, 6, 3, 1}; for (int i = 0; i < arr.length - 1; i = i + 1) { for (int j = 0; j < arr.length - 1 - i; j = j + 1) { if (arr[j] > arr[j + 1]) { int temp = arr[j]; arr[j] = arr[j + 1]; arr[j + 1] = temp; } } } for (int i = 0; i < arr.length; i = i + 1) { System.out.print(arr[i] + " "); } }}1 2 3 6 7
Two ideas are doing the work. The swap uses a temp variable to hold one value while the two slots trade places, because if you just wrote arr[j] = arr[j+1] first you would overwrite and lose one of them. And the inner loop stops a little earlier each pass (arr.length - 1 - i), because after each pass one more large value is already parked at the end and does not need checking again. Step through it and watch the largest values drift right until the row reads 1 2 3 6 7.
What if you do ask for a slot that does not exist? Java does not quietly hand back garbage the way C might. It stops the program with a clear, named error: an ArrayIndexOutOfBoundsException. The interpreter reports it for you, so let us trigger one on purpose. This loop is wrong by exactly one: it uses <= where it should use <.
public class Main { public static void main(String[] args) { int[] days = {9, 14, 7}; for (int i = 0; i <= days.length; i = i + 1) { System.out.println("day " + i + ": " + days[i]); } }}day 0: 9 day 1: 14 day 2: 7 ArrayIndexOutOfBoundsException: index 3 is outside 0..2
Trace it by hand. It prints day 0, day 1, and day 2 happily, then i becomes 3. Because the condition is i <= days.length, that is 3 <= 3, which is true, so the loop runs one more time and reaches for days[3]. But the valid indices are only 0, 1, 2. Index 3 is off the end, and Java stops with an out-of-bounds error naming the bad index 3 and the valid range 0..2. The fix is the single character we kept stressing: use <, not <=.
3) and the valid range of slots (0..2). When the bad index is exactly equal to the length, that screams “off-by-one, you used <= or forgot the minus one”. Knowing this turns a scary red error into a one-second fix.int[][], perfect for a game board or a table. Two-dimensional arrays build directly on the indexing and traversal you just learned, so make sure the single-row walk feels automatic first.Try each one yourself first, then open the answer.
int[] a = {5, 8, 13, 21};, what is a.length, and what is the index of the last slot?int[] b = new int[4]; runs, and nothing else, what does System.out.println(b[2]); print? Why?scores.length and scores.length(). Which is right for an array, and where does the other form belong?3, but it crashes. What goes wrong, and what is the one-character fix?for (int i = 0; i <= 3; i = i + 1) System.out.println(a[i]);max with temps[0] instead of with 0? Run this buggy version, where every value is negative, to see the wrong answer it gives.Take these away. They continue exactly what we just did.
int[] nums = {4, 9, 2, 7, 1}; and write a for loop that adds every element into a running total, then prints the sum. Trace it by hand first, then run it and confirm.new int[6], then use a loop to fill slot i with the value i * i (so the squares 0, 1, 4, 9, 16, 25). Print each slot on its own line. Confirm slot 5 holds 25 and there is no slot 6.n has its last element at index n - 1, and why a loop guarded by i <= n always crashes. Use the words index, length, and bounds.