Parameters and Arguments in Subroutines
Modifiers appear at the front of a subroutine definition and set characteristics such as whether it is static or public.
Why Programmers Read the Header First
Imagine a program that needs the same job done in three different places. You could copy the same lines of code three times, or you could write those lines once and let the rest of the program use them whenever they are needed. A subroutine is the second option: a block of code that can be called multiple times from different parts of a program.
What do you think happens?
If a program needs the same calculation in several places, where would you rather keep the instructions for it: in one place, or in every place it is needed?
Reveal answer
In one place. A subroutine lets the program write the instructions once and reuse them at every point where they are needed.
Copying the same lines into several places means every copy must be kept up to date. A single subroutine holds the instructions in one spot, and each call reuses them.
The rest of this article follows the way a reader meets a subroutine. Programmers who call a subroutine rarely read its body first. They read the header, because the header describes how the subroutine can be used: what it is, what it hands back, and what it needs to be given. Think of the header as a short contract between the subroutine and anyone who calls it.
Tracing Control Through Repeated Calls
A subroutine does not run just because it exists in a program. It runs when the program reaches a point where it calls it. Because the same block can be called more than once, a single piece of code can serve many moments in a single run of the program. The word called is the important one.
Consider a small generated example. A subroutine named printRow prints one line of output. The main program calls printRow at two different points, once with the value 3 and once with the value 7. The diagram shows the path control takes: main pauses at each call site, control jumps into printRow, the subroutine finishes, and control returns to the line in main that follows the call.
Tracing the printRow program
main calls printRow(3), then does one more line of work, then calls printRow(7). What is printed, and in what order?
- 1Step 1
main reaches the first call. Execution jumps into
printRow, and its parameter n receives the value 3. - 2Step 2
printRowprints 3 and finishes. Control returns to the line in main directly after the first call. - 3Step 3
main runs its next line, then reaches the second call. Execution jumps into
printRowagain, this time with n holding 7. - 4Step 4
printRowprints 7 and finishes. Control returns to main, which continues with the lines after the second call.
The output is 3 then 7. One block of code produced two outputs because it was called twice.
Reading a Subroutine Header
Every subroutine begins with a header line that comes before the braces and the code inside them. The header reads from left to right: modifiers at the front, then the return type, then the subroutine's name, then the parameter list in parentheses. For each piece, the question to keep in mind is the same: what does this part promise or require when someone uses the subroutine?
Put the parts together and the header is a compact summary of how the subroutine is used. The modifiers tell you about its characteristics, the return type tells you what comes back, the name identifies the block, and the parameter list tells you what must be supplied when you call it. The header therefore answers several questions before you read a single line of the body.
Declaring Multiple Parameters Correctly
When a parameter list holds more than one parameter, each parameter needs its own type. The correct form for two double values is double x, double y. Writing double x, y is incorrect, because y then has no type of its own. The parameters are separated by commas, and each one is read as a pair of type and name.
3
7computeAreais a function: its return type is double, so it hands a value back to the callerprintRowis a void subroutine: nothing comes back, so the call only prints- Each parameter in
computeAreahas its own type: double width, double height - main calls
printRowtwice, which is why its output appears twice in the run
In the call computeArea(3.0, 4.5), the first argument fills the first parameter, width, and the second fills height. The parameter list is therefore a contract about order as well as type. If a caller swapped the arguments to computeArea(4.5, 3.0), the subroutine would still receive two values of the right type, but width would now hold 4.5 and height would hold 3.0. The program would run, but the meaning of the inputs would be reversed.
Mistakes When Writing Parameter Lists
Common mistake Giving only the first parameter a type
What it looks likedouble x, y
Why it failsEach parameter needs its own type. The declaration gives x a type, but y has no type of its own.
Do this insteaddouble x, double y
Common mistake Treating a void subroutine as if it returns a value
What it looks likeint total = printRow(3);Why it failsA subroutine whose return type is void hands nothing back, so there is no value to store.
Do this insteadCall printRow(3); on its own line, and use a function with a non-void return type if you need a result.
Common mistake Assuming a modifier decides what the parameters are
What it looks likeReading static in the header and expecting it to say what input is accepted
Why it failsModifiers set characteristics such as static or public. The accepted inputs are declared in the parameter list.
Do this insteadRead the parameter list in the parentheses to learn what the subroutine needs.
Common mistake Passing arguments in the wrong order
What it looks likecomputeArea(4.5, 3.0) when the intended width is 3.0Why it failsArguments are matched to parameters by position, so the first value always goes to the first parameter.
Do this insteadLine up each argument with the parameter it is meant to fill, in the same order as the list.
Common mistake Forgetting that a subroutine runs only when it is called
Where ThreeN2.java Uses Subroutines
The source material points to a concrete program that uses subroutines: ThreeN2.java. It is introduced in Section 4.4 as an improved version of the 3N+1 program, and the source describes it as a program that uses subroutines and prints its output in neat columns. The source does not list the individual subroutines inside ThreeN2.java or show their code, so this section does not describe them in detail.
What the source does establish is the reason the program uses subroutines. The first reason is code organization: separating work into named blocks makes the program easier to read and manage. The second reason is output formatting: the program prints its results in neat columns, and the subroutines are part of how that formatting is achieved.
Open ThreeN2.java and find the places where the program calls a named block of code. Compare them with the places where it prints results. For each call you find, note whether the subroutine it reaches is doing computation or formatting output.
Hints
- Look for a method name followed by parentheses where the program is not defining it.
- Output in neat columns is usually produced by the code that prints, so compare the print statements with the calls around them.
Practice: Reading a Header and Tracing Calls
Here is a header: public static void showTotal(int count, double price). Without reading any body, state three things a caller can tell from this header: whether a value comes back, how many inputs are required and of which types, and what the modifiers promise. Then write a main method that calls showTotal twice, with two different sets of arguments, and state where execution resumes after each call.
Hints
- The return type is the word after the modifiers and before the name.
- The parameter list is inside the parentheses, and each parameter has its own type.
Key Takeaways
- A subroutine is a block of code that runs when a program calls it, and the same block can be called many times from different parts of a program.
- The header reads left to right: modifiers set characteristics such as static or public, the return type says what comes back, and the parameter list declares what must be supplied.
- A function's return type names the value it hands back, while a void subroutine returns nothing and is called for its effect.
- Each parameter in a list needs its own type and name, written as type followed by parameter name, and arguments fill parameters by position.
ThreeN2.javauses subroutines to organize its code and to help format its output in neat columns.