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
- Explain why we write methods: less repetition and named ideas
- Define a
voidmethod and call it - Tell a parameter from an argument and pass several arguments in the right order
- Write a method that returns a value and use that value in an expression
- Step in and out of a method in the debugger and read the call stack
- Fix the compiler errors that methods commonly cause
In this lecture
- A method ends repetition and gives an idea a name
- You have been calling methods since the first lecture
- We define a method once and call it by name
- A parameter is a box in the method; an argument is the value you put in it
- A parameter lets one method serve many cases
- Arguments go to parameters by order, not by name
returnsends a value back to whoever called the method- A call fits inside any expression that accepts its value
- A method that returns
booleanbecomes a readable condition - A method can have several
returns, and only one of them runs - A method either does a job or gives back an answer
- Every call gets its own frame and its own boxes
- A method that promises a value must return one on every path
- A call must match the definition in name, count and type
- Review questions
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();
}
}******************** Sales report ******************** Total: 150 ********************
You write the instructions in one place and use them anywhere. To change them, you edit one place.
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.
| Call | What we give it | What it does or gives back |
|---|---|---|
System.out.println("Hi") | A string | Prints it and gives nothing back |
input.nextInt() | Nothing | Gives back the number the user typed |
Math.pow(2, 3) | Two numbers | Gives 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
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
| Part | Meaning |
|---|---|
static | Required on every method we write for now; a later course explains it. |
void | This method gives nothing back |
greet | The 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();
}
}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
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
A variable declared between the parentheses of the definition. Here, name.
static void greet(String name)The value we write in the call. Here, "Sara".
greet("Sara");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");
}
}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);
}
}******************** 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
}
}3
* ** ***
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);
}
}##### ---
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
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.
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.
int means the method promises to give back a whole number.
static int max(int a, int b)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));
}
}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
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));
}
}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
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
}
}5 3
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");
}
}
}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
}
}6
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));
}
}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
}
}5
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
| Compare | void | Returns a value |
|---|---|---|
| Example | printStars(5); | int m = max(3, 7); |
| How it ends | Reaches } | Runs return with a value |
| Where to call it | Only on a line of its own | Usually 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
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));
}
}'void' type not allowed hereShow 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);
}
}***
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?
main, so it cannot be used in a condition. An average has a decimal part, so double fits.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);
}
}25
- Press "Debug line by line"It stops on the first line of
main, and the stack has one frame:main(). - Press "Step into" (F7)The frame
sumOfSquares()appears abovemain(), with boxesa = 3andb = 4. - Press "Step into" againThe frame
square()appears on top withx = 3. The stack now has three frames. - Press "Step out" (Shift+F8)The frame
square()and its boxes disappear, andfirst = 9appears insumOfSquares(). - Press "Next line" (F8)The second call runs in full without stepping into it, and
second = 16appears. - Press "Step out", then "Continue" (F9)You are back in
mainwithanswer = 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?
square, while sumOfSquares and main wait below it.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
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));
}
}missing return statementShow 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));
}
}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;
}
}
if that might not run, so it treats the end of the method as reachable. Use else or a final return.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));
}
}cannot be applied to given typesShow 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));
}
}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"));
}
}incompatible types: String cannot be converted to intShow the fix
public class WrongType {
static int twice(int n) {
return n * 2;
}
public static void main(String[] args) {
System.out.println(twice(21));
}
}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();
}
}cannot find symbolShow the fix
public class Undefined {
static void printLine() {
System.out.println("-----");
}
public static void main(String[] args) {
printLine();
}
}-----
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?
void concerns only what comes out of the method. What goes in is set by the parameters between the parentheses, and a void method can take parameters, like printStars(int count).In a file with five methods written before main, where does the run start?
main, and the others run only when called.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
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.