Lesson 6Phase 1: First steps
Arrays, one dimension
Storing many values under one name, indexing from zero, and walking an array with a loop.
By BasithUpdated 60 min
- array
- index
- length
- new int[n]
- array literal
- bounds
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 lesson solves. An array is a single name that holds many values in a row.
- Say, in one sentence, what an array is and why loose variables stop working.
- Build an array two ways: with values listed, and with
new int[n]. - Read and write any slot using an index, counting from
0. - Use
.lengthand walk an entire array with aforloop or a for-each loop. - Print a whole array with
Arrays.toString, and copy one without sharing it. - Explain why
a[a.length]is always one step too far.
Fifty variables is fifty problems#
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); }}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.
Key ideaLoose 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.
Two ways to build an array#
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.
One: list the values you already have
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]); }}Two: ask for empty slots with new int[n]
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]); }}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] = ....Indexing: counting starts at zero#
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.
How many slots? Use .length
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 later in this lesson.int[] a = {4, 8, 15, 16, 23};, what is a[a.length - 2]?Walking an array with a for loop#
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"); }}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.
Key ideaThe standard 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.
Most Java code writes the update as i++, the shorthand from operators and casting, so you will often see the same walk written for (int i = 0; i < a.length; i++). It does exactly the same thing.
Printing a whole array#
You might expect System.out.println(scores) to show the values. It does not. It prints something like [I@1b6d3586: [Iis Java's code for “array of int”, and the part after the @is a number that identifies the array and can change from one run to the next. To see the values, walk the array as above, or let Java's library do the formatting:
import java.util.Arrays; public class Main { public static void main(String[] args) { int[] scores = {10, 20, 30}; double[] prices = {2.5, 4.0}; String[] names = new String[2]; System.out.println(Arrays.toString(scores)); System.out.println(Arrays.toString(prices)); System.out.println(Arrays.toString(names)); }}Arrays is a class in java.util full of ready-made helpers for arrays, so it needs an import, as Scanner did. Arrays.toString(scores) builds the text [10, 20, 30]: the values in square brackets, separated by commas. It works for every kind of array, which is why the prices print as [2.5, 4.0] and the two empty String slots as [null, null].
A real task: find the largest value
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); }}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.
Cheapest is 3 at index 2.Tap a line, then tap where it should go. Or use the arrows.
The for-each loop: when you do not need the index#
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); } }}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).
import java.util.Arrays; public class Main { public static void main(String[] args) { int[] prices = {5, 10, 15}; for (int p : prices) { p = p * 2; } System.out.println(Arrays.toString(prices)); }}This for-each loop doubles p on every pass. What does the last line print?
It prints [5, 10, 15]: the array has not changed. On each pass, p is a copy of the value in the current slot. Doubling the copy changes p and nothing else, and the next pass overwrites p with the next value. A for-each loop also hides the index, so it cannot look at two positions at once either. To change the slots themselves, use the counting loop and write through the index: prices[i] = prices[i] * 2;.
Summing and averaging an array#
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); }}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.
double and print it, then print every score that is above the average, one per line, in the order they appear in the array.Putting an array in order: bubble sort#
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] + " "); } }}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.
temp? What goes wrong with just arr[j] = arr[j + 1]; followed by arr[j + 1] = arr[j];?Copying an array: two names, one row#
Bubble sort rearranged arr itself, so the original order is gone. Often you want to keep the original and work on a copy. Here is the obvious first try, with an array of scores and the line int[] backup = scores;. Decide what this program prints before you run it.
public class Main { public static void main(String[] args) { int[] scores = {70, 85, 90}; int[] backup = scores; backup[0] = 0; System.out.println("scores[0] is " + scores[0]); }}The program changes backup[0] and then prints scores[0]. What appears?
It prints scores[0] is 0. The line int[] backup = scores; did not copy any values. An array variable holds a reference: directions to where the row of slots lives in memory. The assignment copied the directions, so both names now lead to the same row, and a change made through either name shows up through the other. Two names for one array like this is called aliasing.
To get a real copy, make a new array of the same length and copy the values across, slot by slot. Step through this version and watch the memory view: this time there are two separate rows, and changing one leaves the other alone.
import java.util.Arrays; public class Main { public static void main(String[] args) { int[] scores = {70, 85, 90}; int[] backup = new int[scores.length]; for (int i = 0; i < scores.length; i = i + 1) { backup[i] = scores[i]; } backup[0] = 0; System.out.println(Arrays.toString(scores)); System.out.println(Arrays.toString(backup)); }}The output is [70, 85, 90] for scores and [0, 85, 90] for backup. The library can do the copying for you: int[] backup = Arrays.copyOf(scores, scores.length); makes the new array and fills it in one line. The second argument is how long the copy should be.
Key idea
b = agives the same array a second name. To get a separate array, copy the values into a new one, with a loop or withArrays.copyOf.
reversed so that it holds the values of original back to front, and leave original as it is. Both arrays are printed at the end.Stepping off the end#
What if you do ask for a slot that does not exist? Some languages quietly hand back whatever happens to sit in memory past the end. Java never does. It stops the program with a clear, named error: an ArrayIndexOutOfBoundsException. Run this loop to trigger one on purpose. It 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]); } }}ArrayIndexOutOfBoundsException: Index 3 out of bounds for length 3
Array positions run from 0 up to length - 1. This index fell outside that range.
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 ArrayIndexOutOfBoundsException: Index 3 out of bounds for length 3. The fix is the single character we kept stressing: use <, not <=.
3) and the length of the array (3). When the bad index equals the length, you almost certainly have an off-by-one: a <= that should be <, or a missing minus one. Knowing this turns a scary red error into a one-second fix.int[][], for a game board or a table. Both build on the indexing and traversal you just learned, so make sure the single-row walk feels automatic first.The array problem set#
Here is the real practice: ten array problems, plus a bonus, each solved using only arrays and for loops, nothing fancier. Read each one, predict the output, then press Run and step through to check yourself. These are the exact moves you will reach for again and again.
1. Circular neighbor sum
Build a new array where each element is the sum of its left and right neighbors. The array wraps around: the first element's left neighbor is the last, and the last element's right neighbor is the first.
public class Main { public static void main(String[] args) { int[] arr = {2, 4, 6, 8}; int[] result = new int[arr.length]; for (int i = 0; i < arr.length; i = i + 1) { int left; int right; if (i == 0) { left = arr[arr.length - 1]; } else { left = arr[i - 1]; } if (i == arr.length - 1) { right = arr[0]; } else { right = arr[i + 1]; } result[i] = left + right; } for (int i = 0; i < result.length; i = i + 1) { System.out.print(result[i] + " "); } }}2. Mirror difference array
Each element becomes the absolute difference between it and its mirrored counterpart from the other end of the array.
public class Main { public static void main(String[] args) { int[] arr = {5, 2, 8, 3}; int[] result = new int[arr.length]; for (int i = 0; i < arr.length; i = i + 1) { int mirror = arr.length - 1 - i; int diff = arr[i] - arr[mirror]; if (diff < 0) { diff = -diff; } result[i] = diff; } for (int i = 0; i < result.length; i = i + 1) { System.out.print(result[i] + " "); } }}3. Leader elements
An element is a leader if it is greater than every element to its right. Print all leaders.
public class Main { public static void main(String[] args) { int[] arr = {16, 17, 4, 3, 5, 2}; for (int i = 0; i < arr.length; i = i + 1) { boolean leader = true; for (int j = i + 1; j < arr.length; j = j + 1) { if (arr[j] > arr[i]) { leader = false; break; } } if (leader) { System.out.print(arr[i] + " "); } } }}4. Array wave formation
Rearrange the array into a wave, where each adjacent pair is swapped so the values rise and fall.
public class Main { public static void main(String[] args) { int[] arr = {1, 2, 3, 4, 5}; for (int i = 0; i < arr.length - 1; i = i + 2) { int temp = arr[i]; arr[i] = arr[i + 1]; arr[i + 1] = temp; } for (int i = 0; i < arr.length; i = i + 1) { System.out.print(arr[i] + " "); } }}5. Longest increasing streak
Find the length of the longest run of consecutive increasing values.
public class Main { public static void main(String[] args) { int[] arr = {1, 2, 3, 1, 2, 3, 4}; int current = 1; int max = 1; for (int i = 1; i < arr.length; i = i + 1) { if (arr[i] > arr[i - 1]) { current = current + 1; } else { current = 1; } if (current > max) { max = current; } } System.out.println(max); }}6. Frequency count, without a HashMap
Print how many times each unique value occurs, using only arrays and loops. Skip a value if you have already counted it earlier.
public class Main { public static void main(String[] args) { int[] arr = {4, 2, 4, 3, 2, 4}; for (int i = 0; i < arr.length; i = i + 1) { boolean alreadyCounted = false; for (int k = 0; k < i; k = k + 1) { if (arr[i] == arr[k]) { alreadyCounted = true; break; } } if (alreadyCounted) { continue; } int count = 0; for (int j = 0; j < arr.length; j = j + 1) { if (arr[i] == arr[j]) { count = count + 1; } } System.out.println(arr[i] + " -> " + count); } }}7. Alternate positive and negative
Lay out positives at even indices and negatives at odd indices, so the signs alternate.
public class Main { public static void main(String[] args) { int[] arr = {1, 2, 3, -1, -2, -3}; int[] result = new int[arr.length]; int index = 0; for (int i = 0; i < arr.length; i = i + 1) { if (arr[i] > 0) { result[index] = arr[i]; index = index + 2; } } index = 1; for (int i = 0; i < arr.length; i = i + 1) { if (arr[i] < 0) { result[index] = arr[i]; index = index + 2; } } for (int i = 0; i < result.length; i = i + 1) { System.out.print(result[i] + " "); } }}8. First repeating element
Find the first value that appears more than once, then stop. The classic double for loop. The return; on its own line ends main straight away, and with it the program.
public class Main { public static void main(String[] args) { int[] arr = {7, 4, 5, 7, 3, 5}; for (int i = 0; i < arr.length; i = i + 1) { for (int j = i + 1; j < arr.length; j = j + 1) { if (arr[i] == arr[j]) { System.out.println(arr[i]); return; } } } }}9. Array mountain check
Decide whether the array strictly rises, then strictly falls, with the peak at neither end. Like problem 8, it uses return; to end main as soon as the answer is known.
public class Main { public static void main(String[] args) { int[] arr = {1, 3, 7, 5, 2}; int peak = 0; for (int i = 0; i < arr.length - 1; i = i + 1) { if (arr[i] < arr[i + 1]) { peak = peak + 1; } else { break; } } if (peak == 0 || peak == arr.length - 1) { System.out.println(false); return; } for (int i = peak; i < arr.length - 1; i = i + 1) { if (arr[i] <= arr[i + 1]) { System.out.println(false); return; } } System.out.println(true); }}10. Balance point
Find an index where the sum of everything on the left equals the sum of everything on the right.
public class Main { public static void main(String[] args) { int[] arr = {1, 7, 3, 6, 5, 6}; for (int i = 0; i < arr.length; i = i + 1) { int leftSum = 0; int rightSum = 0; for (int j = 0; j < i; j = j + 1) { leftSum = leftSum + arr[j]; } for (int j = i + 1; j < arr.length; j = j + 1) { rightSum = rightSum + arr[j]; } if (leftSum == rightSum) { System.out.println(i); break; } } }}Bonus: array cipher
Each number is a letter: 1 is A, 2 is B, up to 26 is Z. Turn the array into a word. This leans on the char-and-number trick from operators and casting.
public class Main { public static void main(String[] args) { int[] arr = {8, 5, 12, 12, 15}; for (int i = 0; i < arr.length; i = i + 1) { char ch = (char) ('A' + arr[i] - 1); System.out.print(ch); } }}Try it
Answer each one in your head or on paper 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.int[] b = a; the program changes b[1], then points b at a brand new array. Work it out before you run it.Practice
Work through these on your own. Each one builds on this page.
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.int[5], then prints them in reverse order on one line, then prints the largest. Use the Scanner recipe from making decisions, and test it with the input 4, 9, 2, 7, 1, one per line.Further reading#
- Creating arrays in your programs, on dev.java, the official Java learning site
- java.util.Arrays in the Java SE 25 API documentation: toString, copyOf, equals, sort and the other helpers
- Arrays in the Java Language Specification, chapter 10, the exact rules for creating and indexing arrays
Short guides on this topic
Quick answers to what people search for about it, with code to run.
Spotted a mistake, or a part that did not make sense? Report it by email