Free for students · Ad-free · WCAG 2.1 AA Compliant · Accessibility

Methods: How to Write Them

Lesson ~10 min read 8 MCQs

In simple terms: In simple terms, methods are a class's action verbs, letting objects perform tasks like calculating a value or changing their internal data.

Why this matters

Imagine you're at a high-tech vending machine. You want a soda. You press the button for "Cola" (that's like calling a method). The machine whirs, and a can of soda drops into the slot. You received something back—a value! Now, imagine you press a button to "Add $1 to Credit." The screen updates, but nothing comes out of the machine. It just changed its internal state.

In Java, our objects are like that vending machine. We need to write the instructions—the methods—that tell them what to do when we "press their buttons." Some methods will give us a value back (like the soda), while others will just change the object's data (like adding credit).

Methods can either return a value (like getting soda) or just perform an action (like adding credit).

In this lesson, we'll learn how to write both kinds of methods, giving our objects the behaviors they need to be useful.

Concept overview

flowchart TD
    A[Start: Main Program] --> B{Call myObject.doTask(5)};
    B --> C[Control transfers to doTask method];
    C --> D[Parameter 'x' in doTask gets a copy of value 5];
    D --> E[doTask method executes its logic];
    E --> F{Is doTask a void method?};
    F -- Yes --> G[Control returns to Main Program];
    F -- No --> H[Calculate return value, e.g., 'result'];
    H --> I[Return 'result' and control to Main Program];
    G --> J[Main Program continues execution];
    I --> J;
    J --> K[End];
This diagram shows a flowchart of a method call in Java. It starts in the main program, shows control transferring to a method, and then branches based on whether the method is void or returns a value, before finally returning control to the main program.

Core explanation

Alright, let's dive into writing the code that brings our objects to life. If instance variables are the nouns (the data an object has), methods are the verbs (the actions an object can do).

The Two Flavors of Methods: void and Non-void

Every method you write will fall into one of two categories, and the difference is simple: does it give you a value back when it's done?

Comparing `void` (do-er) and non-`void` (giver) methods.

1. void Methods: The Do-ers

A void method is like telling a friend, "Hey, can you please go turn on the light?" They perform an action, but they don't hand you anything back. The job is just... done.

In Java, the keyword void in a method's signature tells us that this method will not return any value.

public class LightSwitch {
    private boolean isOn;

    // A void method that performs an action
    public void flipSwitch() {
        isOn = !isOn; // Toggles the boolean value
        System.out.println("Click!");
    }
}

Notice the public void flipSwitch(). The void keyword is your signal. This method's only job is to change the isOn instance variable. When you call it, it does its work and that's it.

These are often mutator methods (or "setters"). A mutator's purpose is to mutate, or change, an object's state—specifically, the values of its instance variables.

2. Non-void Methods: The Givers

A non-void method is like asking a friend, "What's the temperature outside?" They check, and then they tell you a specific value, like "68 degrees." They are giving you information back.

Instead of void, the method signature will specify the type of data it promises to return. This could be int, double, boolean, String, or any other type.

public class Thermometer {
    private double currentTempF;

    // A non-void method that returns a value
    public double getTemperature() {
        return currentTempF;
    }
}

Here, public double getTemperature() promises to return a double. And it delivers on that promise with the return statement.

These are often accessor methods (or "getters"). An accessor's job is to provide access to an object's state without changing it. It gives you a copy of the value of an instance variable.

The return Statement: Handing Back the Result

In every non-void method, you must have a return statement that provides a value matching the declared return type.

Think of return as the final act of a method. It does two things:

  1. It hands a value back to wherever the method was called.
  2. It immediately stops the method and returns control flow back to the caller.
public int addFive(int number) {
    return number + 5;
    // System.out.println("This will never print!"); // ERROR: unreachable code
}

Once that return happens, the addFive method is finished.

Using Parameters: Giving Methods What They Need

What if a method needs some information to do its job? When you order a pizza, you have to tell them what toppings you want. Those toppings are parameters.

Parameters are variables listed inside the method's parentheses. When you call the method, you provide values for them, which are called arguments.

public class BankAccount {
    private double balance;

    // A mutator method with a parameter
    public void deposit(double amount) {
        if (amount > 0) {
            balance = balance + amount;
        }
    }

    // A non-void method with a parameter
    public double calculateFutureValue(int years) {
        // A simple (and not very accurate) interest calculation
        double futureValue = balance * (1 + 0.02 * years);
        return futureValue;
    }
}

When we call myAccount.deposit(100.50), the value 100.50 is the argument. Inside the deposit method, the parameter variable amount is initialized with the value 100.50.

The Golden Rule of Primitives: Pass-by-Copy

This next concept is critical for the AP exam, so let's be very clear.

When you pass a primitive type (int, double, boolean, char) as an argument to a method, Java makes a copy of the value.

The method receives the copy, not the original variable. It's like you wrote a number on a sticky note, and you hand a photocopy of that note to your method. The method can scribble all over the photocopy, but your original sticky note remains unchanged.

Let's see this in action.

public class Tester {
    public void tryToChange(int x) {
        x = x + 10; // We are changing the copy
        System.out.println("Inside method, x is: " + x); // Prints 15
    }

    public static void main(String[] args) {
        Tester myTester = new Tester();
        int myNumber = 5;

        System.out.println("Before method call, myNumber is: " + myNumber); // Prints 5

        myTester.tryToChange(myNumber); // Pass the value of myNumber

        System.out.println("After method call, myNumber is: " + myNumber); // Still prints 5!
    }
}

See it in action

Java Code

      
      
Call Stack
Stack is empty — waiting for first call.
Step 0 / 0

Worked examples

Let's build a class from scratch to see these concepts in action. We'll create a GamePlayer class for a simple arcade game.

Example 1: The GamePlayer Class

Problem: Create a GamePlayer class that tracks a player's username and score. It should have:

  1. A way to get the player's score.
  2. A way to increase the player's score by a specific amount.
  3. A way to reset the score back to zero.

Solution Walkthrough:

First, let's define the class and its instance variables.

public class GamePlayer {
    private String username;
    private int score;

    // Constructor to initialize the player
    public GamePlayer(String name) {
        this.username = name;
        this.score = 0; // Players always start with 0 points
    }

Now, let's tackle the requirements one by one.

  1. 1
    Get the player's score
    This sounds like we need to access data. This calls for an accessor method. It needs to give us a value back (the score), so it will be non-void. The score is an int, so the method must return an int.
    // Accessor method ("getter")
    public int getScore() {
        return this.score;
    }

    Why? We use return this.score; to send a copy of the score value back to whoever called the method. It's public so code outside this class can use it.

  2. 2
    Increase the score
    This action changes the player's state. This is a job for a mutator method. It needs to know how much to increase the score by, so it will need a parameter. Since its job is just to change the score and not to report anything back, it should be void.
    // Mutator method
    public void increaseScore(int points) {
        if (points > 0) {
            this.score = this.score + points;
        }
    }

    Why? We declare it void because it doesn't return a value. The int points parameter receives the value passed in when the method is called. We update this.score using that value.

  3. 3
    Reset the score
    This is another action that changes state, so it's another mutator. It doesn't need any input, it just sets the score to 0. It's a void method.
    // Mutator method
    public void resetScore() {
        this.score = 0;
    }

    Why? Simple and direct. It changes the instance variable score to 0. No return value is needed.

Putting it all together in a main method:

public static void main(String[] args) {
    GamePlayer player1 = new GamePlayer("Maya");

    System.out.println("Initial score: " + player1.getScore()); // Prints 0

    player1.increaseScore(50);
    System.out.println("Score after first round: " + player1.getScore()); // Prints 50

    player1.increaseScore(25);
    System.out.println("Score after second round: " + player1.getScore()); // Prints 75

    player1.resetScore();
    System.out.println("Score after reset: " + player1.getScore()); // Prints 0
}
Tracing the `increaseScore` method for a `GamePlayer`.
A simple `GamePlayer` class with its methods.

Try it yourself

Ready to write your own? Let's model a CoffeeMug.

Your Task: Create a CoffeeMug class with a private double ounces; instance variable.

Write the following methods:

  1. A constructor public CoffeeMug(double startOunces) that initializes the mug.
  2. An accessor method public double getOunces() that returns the current amount of coffee.
  3. A void mutator method public void takeSip(double sipSize) that decreases the ounces in the mug. Make sure the ounces can't go below zero!
Logic for the `takeSip` method, ensuring ounces don't go below zero.