Built-in Subroutines and Functions
A subroutine is a named set of program instructions designed to perform a task.
Why Repeated Work Needs a Name
Programs often need to do the same kind of job in several different places. Suppose a program must print the same divider line three times in one run. One approach is to copy the same lines of code three times. Another is to write those lines once and let the rest of the program use them whenever they are needed. The second option is the idea behind a subroutine.
What do you think happens?
If a program needs the same calculation or the same printed output in several places, would you rather keep its instructions in one place or in every place it is needed?
Reveal answer
One place. A subroutine groups the instructions for a task, gives the group a name, and lets the program refer to that name wherever the task is needed.
Keeping one copy means a fix or change to the task happens once, not in every location. The rest of this article shows how the name and the call make this work.
What a Subroutine Is
A subroutine is a named set of program instructions designed to perform a task. It is a block of code that can be called multiple times from different parts of a program.
Two ideas are packed into this definition. The first is grouping: several instructions that together accomplish one task are kept as one unit. The second is naming: that unit has a name, so the program can refer to the whole task with a short label instead of listing every instruction again. A name stands in for a block of instructions, which is why one short line can replace many lines of code.
Writing a subroutine does not by itself make it perform its task. Grouping and naming the instructions only creates the subroutine. The task is performed when the program uses a subroutine call statement.
Calling a Subroutine Starts Its Work
A subroutine runs when the program calls it. The important word is called. A subroutine does not run just because it exists in the program. When the main program reaches a call statement, it requests that the named task be performed. Once the subroutine finishes its instructions, the main program continues with the line that follows the call. Because the same block can be called more than once, one piece of code can serve many moments in a single run.
Read the diagram as a sequence of messages. The main program stops at the call statement and hands control to the subroutine. The subroutine performs its instructions. Then control comes back to the main program at the line right after the call, and the main program resumes from there. The main program does not repeat the subroutine's instructions itself; it only asks for the task to be done.
Start
----
Middle
----
End
----printDivideris the named group of instructions; its body contains the single print instruction- Each line
printDivider(); is a call statement, which is the request for the task to be performed - The same subroutine is called three times, so the divider appears three times without its instructions being copied
Tracing One Subroutine Through a Run
Now follow the same program through its run, step by step. Notice that there is only one copy of the divider's instructions, but the subroutine is entered three separate times, once from each call statement in main.
Tracing the shared divider through the run
Using the Greetings program above, list what the program prints and count how many times the printDivider instructions execute.
- 1Line 1 of main
Start is printed by main itself. No subroutine is involved yet.
- 2First call
The statement
printDivider()is reached. Control moves to the subroutine, which prints ----. Control then returns to the line after the call. - 3Middle line
main prints Middle directly, then reaches the second call statement.
- 4Second call
Control moves to the same subroutine, which prints ---- again, and returns to main.
- 5End line
main prints End directly, then reaches the third call statement.
- 6Third call
The same subroutine runs a third time and returns to main, which then finishes.
The program prints Start, ----, Middle, ----, End, ----. The single subroutine is entered three times, and its instructions are written only once in the file.
What do you think happens?
If main calls printDivider() four times instead of three, how many lines of ---- are printed?
Reveal answer
Four
Each call statement requests one run of the subroutine, so each call prints one line of ----. The subroutine's instructions do not change; only the number of calls does.
Predefined Subroutines in Java
You do not always need to write every subroutine yourself. Java includes standard classes that contain predefined subroutines. These subroutines have already been written and can be used in a program. A program can therefore accomplish many tasks by calling existing subroutines instead of creating every group of instructions from the beginning.
Using a Subroutine as a Black Box
A subroutine can be treated as a black box. To use it, a programmer needs to know which subroutine to call and what task it provides. The programmer does not need to know its internal instructions or how those instructions were written. The call uses the subroutine as an available service while leaving its internal workings hidden.
The diagram shows the caller's view. Something goes in through the call, the subroutine does its work, and a result comes out. The steps between those two points are the subroutine's internal instructions, and the caller can ignore them as long as it knows what the subroutine does. This is why a programmer can use a predefined subroutine without reading how it was written.
Subroutines in ThreeN2.java
The source describes ThreeN2.java, introduced in Section 4.4, as an improved version of the 3N+1 program. It is described as a program that uses subroutines and prints its output in neat columns. The source gives two reasons for this use. The first is code organization: separating work into named blocks makes the program easier to read and manage. The second is output formatting: the subroutines are part of how the neat columns are produced.
Mistakes Beginners Make with Subroutines
Common mistake Believing a subroutine runs just because it is written in the program
Why it failsA subroutine performs its task only when the program reaches a call statement that requests it.
Do this insteadWrite the call statement at each point where the task is needed.
Common mistake Copying the same instructions into several places instead of naming them once
What it looks likeWriting the divider's print line three times rather than calling one named subroutine three times
Why it failsRepeated copies must all be changed whenever the task changes, and they make the program harder to read.
Do this insteadGroup the instructions into one subroutine and call it wherever needed.
Common mistake Trying to read a subroutine's internal instructions before using it
Why it failsA subroutine can be used as a black box, so the caller only needs to know what task it performs.
Do this insteadConfirm what the subroutine does and what it provides, then use the call.
Common mistake Assuming String methods can be called without a String object to act on
Practice Tracing Repeated Calls
Using the Greetings program from earlier, predict the output if main is changed so that the line printing Middle is followed by two calls to printDivider() in a row, and then the line printing End follows. Write out every line in order, then count how many times the subroutine is entered.
Hints
- Follow the program from the top of main, executing one statement at a time.
- Each call statement sends control to
printDivider, and control returns to the line after the call. - Two calls in a row produce two divider lines before End is printed.
Key Takeaways
- A subroutine is a named set of program instructions designed to perform a task, and it can be called multiple times from different parts of a program.
- A subroutine runs only when a subroutine call statement requests it; after it finishes, control returns to the line after the call.
- Java provides predefined subroutines in standard classes, and String objects contain subroutines for manipulating strings.
- A subroutine can be used as a black box: a caller needs to know what it does and how to call it, but not its internal instructions.
ThreeN2.javauses subroutines to organize its code and to help format its output in neat columns.