Unit 3 · 22 min

3.5 Methods: How to Write Them

A method's header is its promise: the return type says what comes back, the parameters say what goes in.

Summary, objectives and course and exam description (CED) codes

A void method does not return a value; a non-void method returns a single value of its return type, and this is called return by value. A return statement sends the flow of control back to the caller at once. Accessor methods give other classes a copy of a variable's value, mutator methods change it, and a primitive parameter is a copy of its argument.

By the end of this session you can

  • 3.5.A Develop code to define behaviors of an object through methods written in a class using primitive values, and determine the result of calling these methods.

3.5.A3.5.A.13.5.A.23.5.A.33.5.A.43.5.A.53.5.A.63.5.A.73.5.A.8

Reviewed against the CED on

Know this already? Jump to the checkpoint.

1LearnThe notes, the traps and how to remember them

1. void and non-void methods

The method header tells you whether a method returns a value.

Kind Header Returns
void method public void refill() nothing; the keyword void comes before the method name 3.5.A.1
non-void method public int getAmount() a single value; the return type takes the place of void 3.5.A.2

Here is a complete class in the AP® free-response “class design” style. It is used in every section of this page.

public class WaterBottle
{
    private static int bottlesMade = 0;   // class variable

    private int capacity;   // in milliliters
    private int amount;     // in milliliters

    public WaterBottle(int maxMilliliters)
    {
        capacity = maxMilliliters;
        amount = maxMilliliters;
        bottlesMade++;
    }

    // ----- accessor methods (non-void) -----
    public int getAmount()
    {
        return amount;
    }

    public boolean isEmpty()
    {
        return amount == 0;
    }

    public double percentFull()
    {
        return 100.0 * amount / capacity;
    }

    public static int getBottlesMade()
    {
        return bottlesMade;
    }

    // ----- mutator methods (void) -----
    public void drink(int milliliters)
    {
        if (milliliters > amount)
        {
            amount = 0;
        }
        else
        {
            amount -= milliliters;
        }
    }

    public void refill()
    {
        amount = capacity;
    }

    public String toString()
    {
        return amount + "/" + capacity + " mL";
    }
}
WaterBottle bottle = new WaterBottle(750);
bottle.drink(300);
System.out.println(bottle.getAmount());
System.out.println(bottle.percentFull());
bottle.drink(500);
System.out.println(bottle.isEmpty() + " " + bottle);
bottle.refill();
System.out.println(bottle);

Output:

450
60.0
true 0/750 mL
750/750 mL

Background: toString lets println show the bottle as text. You will read toString methods in class code, but writing one is outside the AP® exam.

A call to a void method is a statement on its own (bottle.refill();). A call to a non-void method is an expression: its value is printed, stored or used in a calculation.

2. Return by value

In a non-void method, a return expression that is compatible with the return type is evaluated, and that value is returned to the caller. This is called return by value 3.5.A.3.

public class Average
{
    public static double mean(int a, int b)
    {
        return (a + b) / 2.0;
    }

    public static int meanRounded(int a, int b)
    {
        return (int) ((a + b) / 2.0 + 0.5);
    }
}
System.out.println(Average.mean(7, 8));
System.out.println(Average.meanRounded(7, 8));

Output:

7.5
8

A double expression is not compatible with an int return type, so this does not compile:

public class BadAverage
{
    public static int mean(int a, int b)
    {
        return (a + b) / 2.0;
    }
}

Compiler says:

error: incompatible types: possible lossy conversion from double to int

A non-void method must return a value on every path through the method:

public class Grader
{
    public static String letter(int score)
    {
        if (score >= 90)
        {
            return "A";
        }
    }
}

Compiler says:

error: missing return statement

3. return ends the method

The return keyword sends the flow of control back to the point where the method or constructor was called 3.5.A.4. Any code that comes after a return statement in sequence is never executed 3.5.A.4. A return statement inside a selection (if) or iteration (loop) statement stops that statement and exits the whole method or constructor 3.5.A.4.

This method searches a string and stops at the first digit it finds:

public class Finder
{
    /** Returns the index of the first digit in s, or -1 if none */
    public static int firstDigit(String s)
    {
        for (int i = 0; i < s.length(); i++)
        {
            String ch = s.substring(i, i + 1);
            if ("0123456789".indexOf(ch) >= 0)
            {
                return i;   // leaves the loop AND the method
            }
        }
        return -1;          // reached only if no digit was found
    }
}
System.out.println(Finder.firstDigit("Room 42B"));
System.out.println(Finder.firstDigit("Lobby"));

Output:

5
-1

A void method can use return; with no value to exit early:

public class Launch
{
    public static void countdown(int start)
    {
        for (int i = start; i >= 0; i--)
        {
            if (i == 2)
            {
                return;
            }
            System.out.println(i);
        }
        System.out.println("Liftoff!");
    }
}
Launch.countdown(5);

Output:

5
4
3

“Liftoff!” is never printed: the return ended the method, not only the loop.

Code placed directly after a return statement can never run, so the compiler rejects it:

public class Doubler
{
    public static int twice(int n)
    {
        return n * 2;
        System.out.println("done");
    }
}

Compiler says:

error: unreachable statement

4. Accessors and mutators

An accessor method lets objects of other classes obtain a copy of the value of an instance variable or a class variable. An accessor is a non-void method 3.5.A.5. In WaterBottle, getAmount returns a copy of amount, and the class method getBottlesMade returns a copy of the class variable bottlesMade.

A mutator method (also called a modifier method) changes the values of instance variables or class variables. A mutator is often a void method 3.5.A.6. In WaterBottle, drink and refill are mutators.

WaterBottle a = new WaterBottle(500);
WaterBottle b = new WaterBottle(1000);
int copy = a.getAmount();
copy = 0;
b.drink(250);
System.out.println(a.getAmount() + " " + b.getAmount());
System.out.println(WaterBottle.getBottlesMade());

Output:

500 750
2

Changing copy did not empty bottle a: the accessor handed out a copy of the value, not the instance variable itself.

Method Accessor or mutator? void?
getAmount() accessor no, returns int
isEmpty() accessor no, returns boolean
drink(int milliliters) mutator yes
refill() mutator yes

5. Parameters and primitive values

Methods with parameters receive values through them and use those values to do their task 3.5.A.7. When the argument is a primitive value (int, double, boolean), the parameter is initialized with a copy of that value. Changes to the parameter have no effect on the argument 3.5.A.8. Passing copies of argument values like this is called call by value (you met it with constructors in topic 1.13).

public class Bonus
{
    public static int addBonus(int points)
    {
        points = points + 10;
        return points;
    }
}
int myPoints = 50;
int result = Bonus.addBonus(myPoints);
System.out.println(myPoints + " " + result);

Output:

50 60

Memory, step by step:

Moment myPoints (in the caller) points (parameter) result
Before the call 50 does not exist does not exist
Start of addBonus 50 50 (a copy) does not exist
After points = points + 10 50 60 does not exist
After the call returns 50 gone 60

Watch out: if the method should change the caller’s variable, the caller must store the returned value: myPoints = Bonus.addBonus(myPoints);.

Lock it in: memory hooks

  • void vs non-voidvoid: does a job, hands nothing back. Non-void: does a job, hands back exactly one value.
  • returnreturn is an exit door: once you go through it, the method is over.
  • Primitive parametersThe method gets a photocopy of the number. Scribbling on the photocopy does not change the original.

Common misconceptions

  • "A method can keep running after its return statement."

    Not quite. return sends control back to the caller immediately. Code after it in the same block never runs (the compiler rejects it as unreachable), and a return inside a loop ends the loop and the method.

  • "If a method changes its int parameter, the caller's variable changes too."

    Not quite. A primitive parameter is a copy of the argument's value. Changing the copy has no effect on the caller's variable.

  • "A method that prints a value returns it."

    Not quite. Printing shows text in the console; returning gives a value back to the caller. A void method that prints cannot be used in an expression like int x = obj.show();

Exam traps

  • A non-void method must return a value on every path, or it does not compile (missing return statement).
  • Returning a double from an int method does not compile; returning an int from a double method is fine (widening).
  • A return inside a for loop stops the loop on the first match; the rest of the loop is skipped.
  • After void method calls, check whether the caller's variable was passed as a primitive: it never changes.

2PracticeRecall it, then check yourself

In 30 seconds

  1. void method: no return value, keyword void in the header. Non-void method: return type in place of void, returns a single value.
  2. The return expression must be compatible with the return type; its value is returned (return by value).
  3. return sends control back to the caller; code after it never runs; a return inside a loop or if exits the whole method.
  4. Accessor: non-void, gives a copy of an instance or class variable's value. Mutator: changes the value, often void.
  5. Parameters receive values; a primitive parameter is a copy, so changing it does not change the argument.

Cover this list, say the points out loud, then take the checkpoint without scrolling back up.

Checkpoint · 6 questions

Checkpoint: Methods: How to Write Them

Pick an answer to mark it. Every answer is explained, and you can try any question again. Your saved score counts first tries only, and stays in this browser.

  1. 1 Consider the following class. The code segment below the class appears in a method in another class. What is printed as a result of executing the code segment? 3.5.A.4
    public class Search
    {
        public static int countUntil(String s, String target)
        {
            int count = 0;
            for (int i = 0; i < s.length(); i++)
            {
                if (s.substring(i, i + 1).equals(target))
                {
                    return count;
                }
                count++;
            }
            return -1;
        }
    }
    
    System.out.println(Search.countUntil("banana", "n") + " " + Search.countUntil("kiwi", "a"));
    Show answer

    Answer: C. In "banana" the first "n" is at index 2. Before it, count was incremented twice (for "b" and "a"), and the return statement exits the loop and the method at once, so 2 is returned. "kiwi" has no "a", so the loop ends and -1 is returned. The option 3 -1 counts the matching letter too, and 4 -1 assumes the loop keeps running after the return.

  2. 2 Consider the following class. The code segment below the class appears in a method in another class. What is printed as a result of executing the code segment? 3.5.A.7, 3.5.A.8
    public class Changer
    {
        public static void update(int a, double b)
        {
            a = a * 2;
            b = b + 1.5;
            System.out.print(a + " " + b + " ");
        }
    }
    
    int x = 4;
    double y = 2.0;
    Changer.update(x, y);
    System.out.print(x + " " + y);
    Show answer

    Answer: B. The parameters a and b are copies of the values of x and y. Inside the method the copies become 8 and 3.5 and are printed. Changes to a primitive parameter have no effect on the argument, so x is still 4 and y is still 2.0. A double always prints with a decimal part, so 2 is wrong.

  3. 3 Consider the following incomplete class. Which of the following can replace /* missing code */ so that getFuel is a correct accessor method, called as c.getFuel()? 3.5.A.2, 3.5.A.3, 3.5.A.5
    public class Car
    {
        private double fuel;
    
        public Car(double startFuel)
        {
            fuel = startFuel;
        }
    
        /* missing code */
    }
    Show answer

    Answer: A. An accessor is a non-void method whose return type matches the value it returns, so public double getFuel() returning fuel is correct. A void method cannot return a value. Returning a double from an int method is a possible lossy conversion and does not compile. The last option needs an argument and returns the parameter, not the instance variable.

  4. 4 The Car class has a mutator addFuel that is intended to increase fuel by liters without letting fuel go above 50.0. If adding liters would go above 50.0, fuel should become exactly 50.0. Which of the following can replace /* missing code */ so that the method works as intended? 3.5.A.6, 3.5.A.7
    public class Car
    {
        private double fuel;
    
        public Car(double startFuel)
        {
            fuel = startFuel;
        }
    
        public void addFuel(double liters)
        {
            /* missing code */
        }
    }
    Show answer

    Answer: D. Adding first and then capping at 50.0 handles both cases. A void method cannot return a value, so return 50.0; does not compile. fuel = liters replaces the fuel instead of adding to it. The <= version does nothing when the sum is too large, so a car with 45.0 that adds 10.0 stays at 45.0 instead of becoming 50.0.

  5. 5 The following method does not compile. Which of the following best explains why? 3.5.A.3, 3.5.A.4
    public boolean isPassing(int score)
    {
        if (score >= 60)
        {
            return true;
        }
        else if (score < 60)
        {
            return false;
        }
    }
    Show answer

    Answer: A. The compiler does not work out that the two conditions cover every score; it only sees that if both conditions were false, the method would reach its end without returning, so it reports a missing return statement. Changing else if (score < 60) to else fixes it. A method may have several return statements, does not need to print, and its return type does not depend on its parameter types.

  6. 6 Consider the following class. The code segment below the class appears in a method in another class. What is printed as a result of executing the code segment? 3.5.A.5, 3.5.A.6
    public class Account
    {
        private int balance;
    
        public Account(int start)
        {
            balance = start;
        }
    
        public int getBalance()
        {
            return balance;
        }
    
        public void deposit(int amount)
        {
            balance += amount;
        }
    }
    
    Account acct = new Account(100);
    int b = acct.getBalance();
    b += 50;
    acct.deposit(20);
    System.out.println(b + " " + acct.getBalance());
    Show answer

    Answer: C. The accessor returns a copy of the value 100, so b becomes 150 without changing the account. The mutator deposit changes the instance variable from 100 to 120. The option 150 170 assumes that changing b also changed balance, and 170 170 treats b and balance as one variable.

3PrevailLock it in for exam day

By the numbers

Name each list from memory, then reveal it to check. Each list shows how many items to recall.

Key terms: flip the cards

Read the term, say the definition out loud, then flip to check. Struggling a little to remember is what makes it stick.

  • Return statementtap to flip

    A statement that sends the flow of control back to the caller, and in a non-void method sends back a value compatible with the return type.

    Example and CED codes
  • Accessor methodtap to flip

    A non-void method that lets objects of other classes obtain a copy of the value of an instance variable or class variable.

    Example and CED codes
  • Mutator methodtap to flip

    A method that changes the values of instance variables or class variables; it is often a void method.

    Example and CED codes
  • Parametertap to flip

    A variable declared in the header of a method or constructor. It receives the value passed in and can be used in the body.

    Example and CED codes
  • Argumenttap to flip

    A value passed into a method or constructor when it is called.

    Example and CED codes
  • Return typetap to flip

    The type of value a method sends back, written before the method name in the header, or void if it returns nothing.

    Example and CED codes
  • Methodtap to flip

    A named block of code that only runs when it is called.

    Example and CED codes
  • Class variabletap to flip

    An attribute declared with the keyword static that belongs to the class, so all objects of the class share a single copy.

    Example and CED codes
  • Call by valuetap to flip

    The way Java passes arguments: each parameter is initialized with a copy of the argument.

    Example and CED codes
  • toStringtap to flip

    A method that returns a String representing an object; println and string concatenation call it automatically.

    Example and CED codes

Questions students ask

What is the difference between a void and a non-void method?

A void method performs an action and returns nothing; its header has void before the name. A non-void method returns a single value; its header has a return type such as int, double, boolean or String instead of void.

What is the difference between an accessor and a mutator?

An accessor (getter) is a non-void method that returns a copy of an attribute's value without changing it. A mutator (setter or modifier) changes the value of an attribute and is often a void method.

Does Java pass primitive values by value?

Yes. When the argument is a primitive value, the parameter is initialized with a copy of that value, so changes to the parameter have no effect on the argument.

What happens to code after a return statement?

It is never executed. If it is in the same block, the compiler reports an unreachable statement error.

Was this page helpful?

No names are ever shown, and every public comment is checked by us first. Please do not include personal details. To get a reply, email [email protected].

↑ Top

Enlarged view of the selected figure