University College of Applied SciencesProgramming 1
العربية
Lecture 11 · 100 min

Methods: Defining and Calling Them

How do we give a group of instructions a name and use it whenever we need it?

By the end of this lecture you will be able to

  1. Explain why we write methods: less repetition and named ideas
  2. Define a void method and call it
  3. Tell a parameter from an argument and pass several arguments in the right order
  4. Write a method that returns a value and use that value in an expression
  5. Step in and out of a method in the debugger and read the call stack
  6. Fix the compiler errors that methods commonly cause
In this lecture
  1. A method ends repetition and gives an idea a name
  2. You have been calling methods since the first lecture
  3. We define a method once and call it by name
  4. A parameter is a box in the method; an argument is the value you put in it
  5. A parameter lets one method serve many cases
  6. Arguments go to parameters by order, not by name
  7. return sends a value back to whoever called the method
  8. A call fits inside any expression that accepts its value
  9. A method that returns boolean becomes a readable condition
  10. A method can have several returns, and only one of them runs
  11. A method either does a job or gives back an answer
  12. Every call gets its own frame and its own boxes
  13. A method that promises a value must return one on every path
  14. A call must match the definition in name, count and type
  15. Review questions
Part one: defining and calling a method

A method ends repetition and gives an idea a name

In the first lecture we said a method is a named group of instructions. The program below shows why we need one: the same loop is written three times.

How many lines would you edit?

Run the program. Then make each line 10 stars instead of 20, and count how many places you had to edit.

public class Report {
    public static void main(String[] args) {
        for (int i = 0; i < 20; i++) {
            System.out.print("*");
        }
        System.out.println();

        System.out.println("Sales report");

        for (int i = 0; i < 20; i++) {
            System.out.print("*");
        }
        System.out.println();

        System.out.println("Total: 150");

        for (int i = 0; i < 20; i++) {
            System.out.print("*");
        }
        System.out.println();
    }
}
Output
********************
Sales report
********************
Total: 150
********************
Write it once

You write the instructions in one place and use them anywhere. To change them, you edit one place.

Name the idea

The name printStars tells you what happens without reading the loop.

You have been calling methods since the first lecture

Someone else wrote these methods, and you call them by name without knowing their details. Today you write your own. Notice the parentheses after each name: that is where we give the method what it needs.

CallWhat we give itWhat it does or gives back
System.out.println("Hi")A stringPrints it and gives nothing back
input.nextInt()NothingGives back the number the user typed
Math.pow(2, 3)Two numbersGives back 2 to the power 3

Math.pow gives back a value, and we print it. What appears?

public class PowerCall {
    public static void main(String[] args) {
        System.out.println(Math.pow(2, 3));
    }
}
Show the output
Output
8.0

Why? Math.pow always gives back a double, which is why we see 8.0 and not 8. A method decides the type it gives back, and today we decide it ourselves.

We define a method once and call it by name

PartMeaning
staticRequired on every method we write for now; a later course explains it.
voidThis method gives nothing back
greetThe method name, in camelCase like a variable
()The parameter list, empty here
{ ... }The body: the instructions it runs

Your first method

The greet method sits inside the class and outside main. Run the program, then add a third call and predict the output before running.

public class Greeting {
    static void greet() {
        System.out.println("Hello!");
        System.out.println("Welcome to Java.");
    }

    public static void main(String[] args) {
        greet();
        greet();
    }
}
Output
Hello!
Welcome to Java.
Hello!
Welcome to Java.

We defined a method, but did we call it?

public class NotCalled {
    static void sayBye() {
        System.out.println("Bye");
    }

    public static void main(String[] args) {
        System.out.println("Start");
        System.out.println("End");
    }
}
Show the output
Output
Start
End

Why? A run always starts at main, whatever order the methods appear in the file. A definition runs nothing; a method works only when it is called.

A parameter is a box in the method; an argument is the value you put in it

Parameter

A variable declared between the parentheses of the definition. Here, name.

static void greet(String name)
Argument

The value we write in the call. Here, "Sara".

greet("Sara");
name"Sara"String

A greeting for every name

Press "Debug line by line", then "Step into" at each call, and watch the box name hold a different value each time. Add a call with your own name.

public class GreetByName {
    static void greet(String name) {
        System.out.println("Hello, " + name + "!");
    }

    public static void main(String[] args) {
        greet("Sara");
        greet("Omar");
    }
}
Output
Hello, Sara!
Hello, Omar!

In static void show(int age) and the call show(19), which is the parameter and which is the argument?

A parameter lets one method serve many cases

Back to the report we started with. The loop now lives in one place, and the length is an argument we can change at will.

A line of stars

Predict the output, then run. Change the length to 10 on every line, then compare how much you edited with the first program.

public class StarReport {
    static void printStars(int count) {
        for (int i = 0; i < count; i++) {
            System.out.print("*");
        }
        System.out.println();
    }

    public static void main(String[] args) {
        int width = 20;
        printStars(width);
        System.out.println("Sales report");
        printStars(width);
        System.out.println("Total: 150");
        printStars(width);
    }
}
Output
********************
Sales report
********************
Total: 150
********************

A triangle of stars

Read a whole number rows, then print a triangle: one star on the first line, two on the second, and so on up to rows. Call printStars inside a loop. Do not print a prompt.

import java.util.Scanner;

public class StarTriangle {
    static void printStars(int count) {
        for (int i = 0; i < count; i++) {
            System.out.print("*");
        }
        System.out.println();
    }

    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        int rows = input.nextInt();
        // Call printStars inside a loop here

    }
}
stdin
3
Expected output
*
**
***
Hint 1

The loop counter runs from 1 up to rows.

Hint 2

The argument is the loop counter itself: printStars(i).

Solution
import java.util.Scanner;

public class StarTriangle {
    static void printStars(int count) {
        for (int i = 0; i < count; i++) {
            System.out.print("*");
        }
        System.out.println();
    }

    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        int rows = input.nextInt();
        for (int i = 1; i <= rows; i++) {
            printStars(i);
        }
    }
}

Arguments go to parameters by order, not by name

Two parameters of different types

A comma separates parameters. Print a line of 8 = signs. Then swap the two arguments in one call and read the compiler message.

public class RepeatSymbol {
    static void printLine(char symbol, int count) {
        for (int i = 0; i < count; i++) {
            System.out.print(symbol);
        }
        System.out.println();
    }

    public static void main(String[] args) {
        printLine('#', 5);
        printLine('-', 3);
    }
}
Output
#####
---

The same method and the same two arguments, in a different order. What does it print?

public class ArgumentOrder {
    static void divide(int top, int bottom) {
        System.out.println(top / bottom);
    }

    public static void main(String[] args) {
        int top = 2;
        int bottom = 10;
        divide(10, 2);
        divide(top, bottom);
    }
}
Show the output
Output
5
0

Why? The first argument always goes to the first parameter. In the second call top holds 2 and bottom holds 10, and dividing two whole numbers drops the fraction, giving 0.

Part two: methods that return a value

return sends a value back to whoever called the method

We write the type of the returned value in place of void. In the call, the returned value takes the place of the call, just as with Math.pow. This is called returning.

In the definition

int means the method promises to give back a whole number.

static int max(int a, int b)
In the call

The returned value is stored in a variable for later use.

int bigger = max(3, 7);

The larger of two numbers

Press "Debug line by line", then "Step into" on the max line. Notice that the box bigger appears in main after the method ends. Test two equal numbers.

public class MaxOfTwo {
    static int max(int a, int b) {
        if (a > b) {
            return a;
        } else {
            return b;
        }
    }

    public static void main(String[] args) {
        int bigger = max(3, 7);
        System.out.println(bigger);
        System.out.println(max(10, 4));
    }
}
Output
7
10

return ends the method at once. What does the program print?

public class ReturnStops {
    static String check(int n) {
        if (n > 0) {
            return "positive";
        }
        return "not positive";
    }

    public static void main(String[] args) {
        System.out.println(check(5));
        System.out.println(check(0));
    }
}
Show the output
Output
positive
not positive

Why? With 5 the condition holds, so execution ends at the first return and never reaches the second. With 0 the condition fails, so it reaches the last return. Each call gives back exactly one value.

A call fits inside any expression that accepts its value

The area in different expressions

We use the returned value in an assignment, in arithmetic, in a condition and in a string join. Add a perimeter method that works out the perimeter of the rectangle and print it.

public class RectangleArea {
    static double area(double width, double height) {
        return width * height;
    }

    public static void main(String[] args) {
        double first = area(3, 4);
        double total = first + area(2.5, 2);
        System.out.println(total);
        if (area(1, 1) < first) {
            System.out.println("The first one is bigger");
        }
        System.out.println("Area: " + area(5, 5));
    }
}
Output
17.0
The first one is bigger
Area: 25.0

Each call is replaced by what it returns. What does this print?

public class ReturnInExpression {
    static int square(int x) {
        return x * x;
    }

    public static void main(String[] args) {
        int total = square(3) + square(4);
        System.out.println(total);
        System.out.println(square(square(2)));
    }
}
Show the output
Output
25
16

Why? 9 + 16 = 25. On the last line the inner call runs first and gives 4, which then becomes the argument of the outer call, giving 16.

Area of a triangle

Write the method triangleArea, which takes base and height as double and returns the area. main reads the two numbers, then prints Area: followed by the result.

import java.util.Scanner;

public class TriangleArea {
    // Write the triangleArea method here

    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        double base = input.nextDouble();
        double height = input.nextDouble();
        // Call triangleArea and print the result

    }
}
stdin
5
3
Expected output
Area: 7.5
Hint 1

The area is half of base times height. Beware of 1 / 2, which is 0 in Java.

Hint 2

The body is one line: return base * height / 2;

Solution
import java.util.Scanner;

public class TriangleArea {
    static double triangleArea(double base, double height) {
        return base * height / 2;
    }

    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        double base = input.nextDouble();
        double height = input.nextDouble();
        System.out.println("Area: " + triangleArea(base, height));
    }
}

A method that returns boolean becomes a readable condition

Is the number even?

Read the condition aloud: "if 7 is even". We name the method as a question starting with is, and return the result of the comparison directly. Write an isPositive method the same way and try it.

public class EvenCheck {
    static boolean isEven(int n) {
        return n % 2 == 0;
    }

    public static void main(String[] args) {
        System.out.println(isEven(4));
        if (isEven(7)) {
            System.out.println("7 is even");
        } else {
            System.out.println("7 is odd");
        }
    }
}
Output
true
7 is odd

Count the even numbers

Read a number n, then use isEven inside a loop to count the even numbers from 1 to n. Print Evens: followed by the count.

import java.util.Scanner;

public class CountEvens {
    static boolean isEven(int n) {
        return n % 2 == 0;
    }

    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        int n = input.nextInt();
        // Count the even numbers from 1 to n, then print the result

    }
}
stdin
6
Expected output
Evens: 3
Hint 1

Declare a counter count starting at 0 before the loop.

Hint 2

Inside the loop: if (isEven(i)) { count++; }.

Solution
import java.util.Scanner;

public class CountEvens {
    static boolean isEven(int n) {
        return n % 2 == 0;
    }

    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        int n = input.nextInt();
        int count = 0;
        for (int i = 1; i <= n; i++) {
            if (isEven(i)) {
                count++;
            }
        }
        System.out.println("Evens: " + count);
    }
}

A method can have several returns, and only one of them runs

The grade letter

Use "Debug line by line" and "Step into" with the call gradeLetter(85), and see where the method ends. Then change the argument to 90 and 89, predicting the letter each time before running.

public class GradeLetter {
    static char gradeLetter(int score) {
        if (score >= 90) {
            return 'A';
        } else if (score >= 80) {
            return 'B';
        } else if (score >= 70) {
            return 'C';
        } else if (score >= 60) {
            return 'D';
        } else {
            return 'F';
        }
    }

    public static void main(String[] args) {
        System.out.println(gradeLetter(85));
        System.out.println(gradeLetter(59));
    }
}
Output
B
F

Ticket price

Write the method ticketPrice, which takes an age and returns the price: under 6 costs 0, 6 to 17 costs 5, and 18 or over costs 10. main prints the prompt Age: , reads the age, then prints Price: and the price on the same line.

import java.util.Scanner;

public class TicketPrice {
    static int ticketPrice(int age) {
        // Replace this line with the rules
        return 0;
    }

    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        System.out.print("Age: ");
        int age = input.nextInt();
        // Print "Price: " and the result of ticketPrice

    }
}
stdin
5
Expected output
Age: Price: 0
Hint 1

Start with the youngest: if (age < 6), then else if (age < 18).

Hint 2

What the user types does not appear in the test output, so the prompt and the result look joined.

Solution
import java.util.Scanner;

public class TicketPrice {
    static int ticketPrice(int age) {
        if (age < 6) {
            return 0;
        } else if (age < 18) {
            return 5;
        } else {
            return 10;
        }
    }

    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        System.out.print("Age: ");
        int age = input.nextInt();
        System.out.println("Price: " + ticketPrice(age));
    }
}

A method either does a job or gives back an answer

ComparevoidReturns a value
ExampleprintStars(5);int m = max(3, 7);
How it endsReaches }Runs return with a value
Where to call itOnly on a line of its ownUsually inside an expression; on a line of its own, its value is lost

twice calculates and returns. Did x change?

public class DiscardReturn {
    static int twice(int n) {
        return n * 2;
    }

    public static void main(String[] args) {
        int x = 5;
        twice(x);
        System.out.println(x);
        System.out.println(twice(x));
    }
}
Show the output
Output
5
10

Why? The line twice(x); works out 10, then the value is lost because nothing uses it, and x stays 5. On the last line println receives the returned value and prints it.

Nothing to print

printStars prints by itself and gives nothing back, yet we put it inside println. Fix the call line.

public class VoidPrint {
    static void printStars(int count) {
        for (int i = 0; i < count; i++) {
            System.out.print("*");
        }
        System.out.println();
    }

    public static void main(String[] args) {
        System.out.println(printStars(3));
    }
}
Compiler message'void' type not allowed here
Show the fix
public class VoidPrint {
    static void printStars(int count) {
        for (int i = 0; i < count; i++) {
            System.out.print("*");
        }
        System.out.println();
    }

    public static void main(String[] args) {
        printStars(3);
    }
}
Output
***

Why? println needs a value to print, and a void method gives none. Call it on a line of its own.

You want a method that works out a student's average so main can use it in a condition. Which return type fits?

Part three: tracing execution and fixing errors

Every call gets its own frame and its own boxes

In a call, execution moves into the method while the caller waits, and when the method ends it returns to the caller and carries on. The program keeps the running calls in the call stack: each call has a frame holding its variables, with the newest frame on top.

Step in and out yourself

Predict the output, then follow the steps below using the debugger buttons.

public class CallStack {
    static int square(int x) {
        int result = x * x;
        return result;
    }

    static int sumOfSquares(int a, int b) {
        int first = square(a);
        int second = square(b);
        return first + second;
    }

    public static void main(String[] args) {
        int answer = sumOfSquares(3, 4);
        System.out.println(answer);
    }
}
Output
25
  1. Press "Debug line by line"It stops on the first line of main, and the stack has one frame: main().
  2. Press "Step into" (F7)The frame sumOfSquares() appears above main(), with boxes a = 3 and b = 4.
  3. Press "Step into" againThe frame square() appears on top with x = 3. The stack now has three frames.
  4. Press "Step out" (Shift+F8)The frame square() and its boxes disappear, and first = 9 appears in sumOfSquares().
  5. Press "Next line" (F8)The second call runs in full without stepping into it, and second = 16 appears.
  6. Press "Step out", then "Continue" (F9)You are back in main with answer = 25, and then the program runs to the end.

The debugger paused at int result = x * x; in the program above. Which frame is on top of the stack?

Trace the execution with your finger from main. What does it print?

public class FlowOrder {
    static void middle() {
        System.out.println("B");
    }

    public static void main(String[] args) {
        System.out.println("A");
        middle();
        System.out.println("C");
        middle();
    }
}
Show the output
Output
A
B
C
B

Why? After each call ends, execution returns to the line after the call in main, so B prints twice, once per call.

A method that promises a value must return one on every path

A path with no return

What does this method give back if a is less than or equal to b? Complete it so it works in every case.

public class MissingReturn {
    static int max(int a, int b) {
        if (a > b) {
            return a;
        }
    }

    public static void main(String[] args) {
        System.out.println(max(2, 8));
    }
}
Compiler messagemissing return statement
Show the fix
public class MissingReturn {
    static int max(int a, int b) {
        if (a > b) {
            return a;
        }
        return b;
    }

    public static void main(String[] args) {
        System.out.println(max(2, 8));
    }
}
Output
8

Why? The compiler checks that every path through the method ends with a value. Here, if the condition is false, the method reaches its end with no value. Notice that the message points at the method's closing }, because reaching it is the problem.

Does this method compile?

static int larger(int a, int b) {
    if (a >= b) {
        return a;
    }
    if (a < b) {
        return b;
    }
}

A call must match the definition in name, count and type

The wrong number of arguments

The method needs two arguments and we gave it one. Add the height 4.

public class WrongCount {
    static int area(int width, int height) {
        return width * height;
    }

    public static void main(String[] args) {
        System.out.println(area(3));
    }
}
Compiler messagecannot be applied to given types
Show the fix
public class WrongCount {
    static int area(int width, int height) {
        return width * height;
    }

    public static void main(String[] args) {
        System.out.println(area(3, 4));
    }
}
Output
12

Why? The compiler adds two lines to the message: required, what the method asks for, and found, what you gave it. Compare them to see what is missing.

The wrong argument type

The quotation marks turned the argument into text. Fix the call.

public class WrongType {
    static int twice(int n) {
        return n * 2;
    }

    public static void main(String[] args) {
        System.out.println(twice("21"));
    }
}
Compiler messageincompatible types: String cannot be converted to int
Show the fix
public class WrongType {
    static int twice(int n) {
        return n * 2;
    }

    public static void main(String[] args) {
        System.out.println(twice(21));
    }
}
Output
42

Why? Passing an argument works like an ordinary assignment: the box int n does not accept text. That is why the message resembles the one from int age = "19";.

An undefined method

One letter separates the two names. Fix the call.

public class Undefined {
    static void printLine() {
        System.out.println("-----");
    }

    public static void main(String[] args) {
        printline();
    }
}
Compiler messagecannot find symbol
Show the fix
public class Undefined {
    static void printLine() {
        System.out.println("-----");
    }

    public static void main(String[] args) {
        printLine();
    }
}
Output
-----

Why? Java is case-sensitive, so printline is not printLine. This is the same message as for an undeclared variable, and its symbol: line shows the name the compiler could not find.

Review questions

What does void mean in a method definition?

In a file with five methods written before main, where does the run start?

Trace it on paper, then check using "Debug line by line".

public class ReviewTrace {
    static int addOne(int n) {
        return n + 1;
    }

    static void show(int n) {
        System.out.println("n = " + n);
    }

    public static void main(String[] args) {
        int value = addOne(4);
        show(value);
        show(addOne(value) * 2);
    }
}
Show the output
Output
n = 5
n = 12

Why? value is 5. Then addOne(5) gives 6, which is multiplied by 2 to give 12 before it becomes the argument of show.