Looping Over Array Elements
A parameter may have an array type such as int[], so one argument can deliver an entire array to a subroutine.
Why One Argument Can Carry a Whole Array
Suppose you want a subroutine that prints every value in an integer array in a tidy format: the values separated by commas and enclosed in square brackets. The subroutine needs to know which array to print, and in Java the way to supply that information is through a parameter. What is new here is that the type of the parameter is itself an array type, so a whole collection of values travels into the subroutine as one argument.
Before reading on, try the following situation. A caller creates an integer array holding the values 42, 17 and 256, then calls the list-printing subroutine on it. Write the exact text you expect on the screen, including where the brackets and commas fall. The rest of this article uses that prediction as a benchmark, so commit to an answer now.
Declaring an Array Parameter
A parameter's type is normally a simple type such as int, but it can also be an array type. Writing int[] as the parameter type means the subroutine accepts an integer array. The name that follows the type, here list, is the name the subroutine uses for the array inside its own body. Only the parameter name matters inside the body, so the subroutine never refers to the caller's variable name.
- int[] is the parameter type: an array of ints, not a single int
- list is the name used for the array inside the body
list.lengthbounds the loop so it visits each position once- The brackets and commas are printed by explicit code, not by the array itself
Creating and Filling the Array First
A subroutine cannot be called with an array that does not exist yet. The array must be created and initialized first, and only then can it be passed as the argument. The source illustrates this with a short segment that declares an array variable, creates an array of three integers, fills in its elements, and then makes the call. The source calls this legal but not very realistic, since the array exists only to be handed to the subroutine. Its values, though, make a useful teaching case.
- numbers is declared as an array variable
- new int[3] creates an array with room for three integers
- The three assignments fill positions 0, 1 and 2
- The call passes the whole array with one argument
Positions in Java arrays are numbered starting from zero. The first value sits at index 0 and the last value sits at index 2. This numbering matters again when the subroutine walks through the array.
How the Array Reaches the Subroutine
When the call printValuesInList(numbers) runs, the name numbers appears in the argument position, and the subroutine receives the array as its list parameter. The subroutine does not need to know the name numbers. It works with the array it was given through list, and every reference to list inside the body refers to that same array. The diagram shows the two names meeting at one array.
Because both names lead to the same array, the subroutine reads exactly the elements the caller filled in. The caller's name and the parameter name are different labels for one collection, so tracing a call means asking which array a name currently refers to, not only what the name is called.
Indexing and the length Property
Inside the subroutine, an element is reached by writing the array name followed by an index in square brackets, as in list[i]. The index says which position to read. The subroutine also needs to know how many positions exist, so it uses the length property of the array. Together these two ideas form the loop that prints the values one at a time.
The valid indexes run from 0 up to length minus one. An array of length 3 has no element at index 3, even though the number 3 appears as its length. Reading past the last index is a common cause of errors in array code, so the loop bound must stop before that position.
Tracing the Loop Pass by Pass
The loop never names the values 42, 17 or 256. It reads the length and the elements from whatever array it receives, so the same subroutine works for any array of integers. The printed brackets come from the two print calls before and after the loop. The commas come from the test inside the loop, which prints a comma only when the current index is not the last one.
Tracing the Call with Three Values
The caller fills numbers with 42, 17 and 256 and calls printValuesInList(numbers). What exact text is printed?
- 1Before the loop
print("[")writes an opening bracket with no newline. - 2Pass with i = 0
list[0] is 42, so 42 is printed. Since 0 < 2 is true, a comma and space follow.
- 3Pass with i = 1
list[1] is 17, printed. Since 1 < 2 is true, another comma and space follow.
- 4Pass with i = 2
list[2] is 256, printed. Since 2 < 2 is false, no comma is printed.
- 5Loop test with i = 3
3 < 3 is false, so the loop stops without visiting index 3.
- 6After the loop
println("]")writes the closing bracket and ends the line.
[42, 17, 256]
What do you think happens?
Before reading on, what exact text does printValuesInList print when numbers holds 42, 17 and 256?
Reveal answer
[42, 17, 256]
The opening bracket is printed before the loop. Each element is printed in turn. The comma test prints a comma after every element except the last, because only the last index equals length minus one. The closing bracket is printed after the loop ends.
Mistakes That Break Array Traces
Common mistake Passing an array before it exists or is filled
What it looks likeCalling printValuesInList(numbers) right after declaring int[] numbers; with no new int[3] and no assignments.
Why it failsThe array must be created and initialized in the calling code before it is passed as the argument.
Do this insteadCreate the array with new, fill its positions, and only then make the call.
Common mistake Assuming the commas come from the array
What it looks likeExpecting the printed list to contain commas automatically because the values are stored together.
Why it failsThe commas and brackets are printed by explicit code in the loop and the surrounding print calls.
Do this insteadTrace the comma test in each pass to see when a comma is printed.
Common mistake Using length as the last valid index
What it looks likeWriting a loop test like i <= list.length, which would try to read list[3] for a three-element array.
Why it failsValid indexes run from 0 to length minus one, so index equal to length is out of range.
Do this insteadUse i < list.length as the loop test.
Common mistake Confusing the caller's variable name with the parameter name inside the subroutine
Practice: Trace a Changed Call
The caller now creates numbers holding only two values, 5 and 9, and calls the same printValuesInList subroutine. Write the exact printed text, and identify which loop pass decides that no comma follows the last value.
Hints
- The loop bound is
list.length, which is now 2. - Check the comma test i <
list.length- 1 for i = 0 and for i = 1. - The brackets come from the print calls outside the loop.
Debugging an Unexpected Printout
When a subroutine that takes an array prints something unexpected, the most useful question is which step first departed from what you predicted. Check the call first: was the array created and filled before the call? Next check the parameter type. Then follow the loop one pass at a time, watching the index, the length check and the comma test. Most surprises in this subroutine come from one of these places, and tracing them in order narrows the search quickly.
Key Takeaways
- A parameter may have an array type such as int[], so one argument can deliver an entire array to a subroutine.
- The caller must create and initialize the array before passing it, and positions are numbered from 0 to length minus one.
- Inside the subroutine, list[i] reads an element, and the length property bounds the loop so every position is visited once.
- Brackets and commas in a printed list come from explicit code, so tracing each loop pass predicts the exact output.