Concepts / Defining Subroutines in Java

Defining Subroutines in Java

Drawing instructions belong inside a subroutine definition, and that subroutine belongs inside a class definition.

  • Programming

Starting From a Working Sample

Suppose you want a Java program that puts a picture on the screen. The fastest route is not to start from a blank file. A sample program already exists that draws a picture of many colored disks, and your job is to replace what it draws with something of your own. For a beginner, the most useful question is not how to write everything from scratch but where, inside a working program, the drawing instructions belong.

Run the sample program first and look at what it produces. Then, before reading the code in detail, ask yourself a simple question: if the picture is wrong, which lines of the program could be responsible? That question is the thread of this article. By the end you should be able to point to the region of code that controls the picture, and to tell apart the lines you are expected to change from the surrounding code you can leave alone.

What do you think happens?

Where in a Java program do drawing instructions have to go?

Reveal answer
Answer:

Inside a subroutine definition, and that subroutine definition has to sit inside a class definition.

Java does not accept loose statements floating on their own. The class is the container for the whole program, and the subroutine is the container for the piece of work that draws the picture.

Why Drawing Code Needs Containers

Java does not accept loose statements floating on their own. Drawing instructions have to sit inside a subroutine definition, and that subroutine definition has to sit inside a class definition. The class is the container for the whole program. The subroutine is the container for the piece of work that draws the picture.

A learner who places a drawing call directly in the class, outside any subroutine, has put it in a location the language will not accept as a running instruction. The diagram below shows the nesting. Read it from the outside in: the class contains the subroutines, and the drawing subroutine contains the body where the drawing work happens.

classSimpleGraphicsStartercontainer for the wholeprogrammain subroutineentry point of the programdrawing bodyloop and Graphics methodcallsdrawPicturesubroutinecontainer for the drawingworkcontainscontainscontains
Which parts of a Java graphics program contain which other parts, so where exactly does the drawing code go?

The class in this sample is named SimpleGraphicsStarter, and the complete program is available in the sample source file SimpleGraphicsStarter.java. The drawing subroutine is the piece you touch. Everything else in the file is scaffolding the author has already written, and you do not need to understand all of it to make your own picture.

Reading the drawPicture Signature

The first line of a subroutine definition is called its signature. For the drawing subroutine, the signature is written as follows.

java

Notice what the signature does not contain: any drawing instruction. Its job is to name the values that arrive from outside the subroutine. The graphics context g is the thing you will call drawing methods on. The width and height tell you how large the drawing area is, so your drawing can adapt to it.

You do not create these values inside drawPicture. They are supplied to the subroutine by the code that calls it, and the subroutine is free to use them. In other words, the parameters are the inputs that show up at the top of the body, ready to be used like any other named value.

What the Sample Body Does

The sample body is mostly one loop. Rather than reading every line at once, follow the control variable that decides how many times the loop runs. This is a good habit when debugging a drawing: find the loop, identify what controls it, and then check whether the picture contains as many items as the loop should produce. The sample's loop runs 500 times.

Inside each pass, the program picks a random center point using width and height, picks one of four colors, sets that color, fills an oval, switches the drawing color to black, and then outlines the same oval. The fill and the outline use the same four numbers, which is why each disk appears with a black border.

You do not need to memorize these details to edit the picture. Knowing which method call does which job is what lets you diagnose a wrong result, and that is the skill the next section builds.

Reading Graphics Method Calls

The Graphics class provides the methods that actually put marks on the drawing area. Three appear in the sample. The setColor method chooses the color for the drawing calls that follow it. The fillOval method draws a solid oval, and drawOval draws only its outline.

Each oval method takes four numbers. In the sample, those numbers are built from the disk center: 50 is subtracted from each coordinate, and 100 is used for both the width and the height. The annotated strip below labels what each part of a fillOval call controls.

fillOvaldraws a solid ovalxdisk center x minus 50ydisk center y minus 50wwidth 100hheight 100
In a call like fillOval(x, y, w, h), which part of the picture does each argument control?

Because setColor affects every call that follows it, the order of your lines matters. This is the single most common reason a picture diverges from what the code appears to say, so when a color is wrong, check the order of setColor calls relative to the fill calls.

Before
setColor(randomColor);
fillOval(x, y, 100, 100);
setColor(Color.BLACK);
drawOval(x, y, 100, 100);

Each disk is filled with the random color, then outlined in black.

After
setColor(Color.BLACK);
fillOval(x, y, 100, 100);
setColor(randomColor);
drawOval(x, y, 100, 100);

The black color is set before the fill, so the disk is filled black instead of the random color.

Subroutines Are Called, Not Just Written

Definition

A subroutine is a block of code that can be called multiple times from different parts of a program.

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.

The important word is called. 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.

Tracing Repeated Calls from main

The sample program's drawing subroutine is called from main, which is the entry point of the program. The sequence below is an illustrative example of how control moves when a main program calls the same subroutine at three different points. The program in this diagram is generated for teaching purposes; it is not a listing of the sample file.

maincalls drawPicture threetimesdrawPictureruns its body each time itis calledcall 1 at first call sitereturn to first call sitecall 2 at second call sitereturn to second call sitecall 3 at third call sitereturn to third call site
When main runs, in what order does control jump to drawPicture, return, and jump again at each call site?

Read the diagram from top to bottom. Each arrow pointing at drawPicture is one call, and each arrow pointing back at main is the return to the place the call was made. The same written block of code runs three times, but it is written only once in the file.

Worked example

Counting drawing runs in a three-call program

A main program contains three calls to drawPicture, and nothing else calls it. How many times does the body of drawPicture run during one execution of main?

  1. 1
    Identify the calls

    There are three call sites in main, each a separate point where the program reaches a call to drawPicture.

  2. 2
    Apply the rule

    A subroutine runs when the program calls it. Each call runs the body once.

  3. 3
    Combine the counts

    Three calls each run the body once, so the body runs three times, even though its code appears only once in the file.

Result

The drawing body runs three times, once per call.

ThreeN2.java and Why Subroutines Help

The source material points to a concrete program that uses subroutines: ThreeN2.java. It is introduced as an improved version of the 3N+1 program and is described as a program that uses subroutines and prints its output in neat columns. Its own code is not reproduced in the source, so this article does not describe its individual subroutines in detail.

The source gives two reasons that ThreeN2.java relies on subroutines. The first is code organization: separating work into named blocks makes the program easier to read and manage. The second is output formatting: the program prints its results in neat columns, and subroutines are part of how that formatting is achieved.

When you open ThreeN2.java yourself, look for the places where the program calls a named block of code, and compare them with the places where it prints results. That comparison shows you the two jobs the subroutines are doing.

Mistakes Beginners Make With Drawing Subroutines

  • Common mistake

    Placing a drawing call directly in the class, outside any subroutine

    What it looks like

    A fillOval call written between the class braces but not inside drawPicture or another subroutine.

    Why it fails

    Java does not accept loose statements. Drawing instructions must sit inside a subroutine definition, which itself sits inside a class.

    Do this instead

    Move the drawing instruction into the body of the drawing subroutine.

  • Common mistake

    Creating a new graphics context inside drawPicture

    Why it fails

    The signature already supplies g, width, and height to the body. Those values are inputs, not things the body needs to build.

    Do this instead

    Use the parameter g to call drawing methods, and use width and height to size the drawing.

  • Common mistake

    Moving the black setColor call above the fill

    What it looks like

    setColor(Color.BLACK) placed before fillOval, so the disk is filled black instead of the random color.

    Why it fails

    setColor affects every drawing call that follows it, so the fill uses whatever color was set most recently.

    Do this instead

    Check the order of setColor calls relative to each fill call when a color looks wrong.

  • Common mistake

    Editing the wrong part of the file when the picture is wrong

Practice: Predicting an Edit

MEDIUM

Before you run anything, predict what happens if you change the black setColor call so that it comes before the fillOval call inside the drawing body. Describe what the disks will look like and explain which method call is responsible for that appearance.

Hints
  • setColor chooses the color for the drawing calls that follow it.
  • Ask which color fillOval will use when it runs, given the line directly above it.
  • The outline drawn by drawOval is a separate call; consider whether changing the fill order affects it.

Key Takeaways

  • Drawing instructions belong inside a subroutine definition, and that subroutine belongs inside a class definition.
  • The signature drawPicture(Graphics g, int width, int height) supplies the graphics context and the drawing area's size, so the body can use them without creating them.
  • setColor affects every drawing call after it, and fillOval and drawOval take four numbers that position and size each oval.
  • A subroutine is a block of code that can be called multiple times from different parts of a program, and it runs each time the program calls it.
  • ThreeN2.java uses subroutines to organize its code and to help format its output in neat columns.