Methods: How to Write Them

Void vs. Non-Void, Revisited for Your Own Classes

Same rule as Ch.4, now applied to methods you write inside your own class: void methods act (no return value); non-void methods compute and return one.

public class Intake
{
    private double currentSpeed;

    public void spin(double speed) // void — acts, doesn't return anything
    {
        currentSpeed = speed;
    }
}

Getters (Accessors)

Since instance variables are private (Lesson 7.1), other classes need a way to read them — a getter: a public method, no arguments, that returns one instance variable's value. By convention its name starts with get.

public double getCurrentSpeed()
{
    return currentSpeed;
}

You don't need a getter for every instance variable — only the ones other code genuinely needs to read. A getter for a boolean field is conventionally named is... or has... instead of get... (matching a boolean field itself, like isDeployed or hasGamePiece from Lesson 7.1) — e.g. isDeployed(), not getIsDeployed().

Setters (Mutators)

A setter is the write-side equivalent: a void method, named starting with set, taking one parameter — the new value — and assigning it to the instance variable.

public void setCurrentSpeed(double newSpeed)
{
    currentSpeed = newSpeed;
}

Think just as hard before writing a setter as before writing a getter. Not every instance variable should be freely settable from outside — sometimes the class should only change its own data through a specific method (like spin(speed) above) that also enforces some rule, rather than through a bare setter that lets anyone assign anything.

toString

toString is a special method Java calls automatically whenever it needs to turn an object into text — including every time you System.out.println(someObject) or concatenate an object with +. Every class actually already has a toString (inherited — Ch.17); writing your own overrides it with something more useful, which is why the method's name and signature (no parameters, returns String) have to match exactly (@Override makes that explicit — also Ch.17).

// assumes 7.1's full Intake, with isDeployed added
public String toString()
{
    return "Intake[speed=" + currentSpeed + ", deployed=" + isDeployed + "]";
}

Without a toString, printing an object directly gives an unhelpful default (something like Intake@1a2b3c) — writing your own gives every System.out.println(myIntake) a genuinely useful message instead.

Method Parameters, Revisited

Same call-by-value rule from Ch.4.1: a primitive parameter (double speed) gets a copy. Changing it inside the method never affects the caller's original variable.

Where Variables Live

Every variable you've written falls into one of three kinds, based on where it's declared:

  • Instance variables — declared inside the class, outside any method (Lesson 7.1). One copy per object; it lives as long as the object does.
  • Parameters — declared in a method's (or constructor's) parameter list. It lives only for that one call — created when the call starts, gone the instant it returns.
  • Local variables — declared inside a method's body, or inside a block like an if or a loop. It lives only inside the block where it's declared — once that block ends, the variable is gone.

Where a variable can be used is its scope; how long it exists is its lifetime. A local variable declared inside an if block doesn't exist outside that block — reading it afterward is a compile error, not a runtime surprise.

public class Intake
{
    // currentSpeed is an instance variable — lives as long as the Intake object does
    private double currentSpeed;

    // targetSpeed is a parameter — lives only during this one call to spin()
    public void spin(double targetSpeed)
    {
        // clamped is a local variable — lives only inside spin()
        double clamped = targetSpeed;
        currentSpeed = clamped;
    } // clamped and targetSpeed both cease to exist here
}

A parameter or local variable can have the same name as an instance variable — inside that method, the closer one (the parameter/local) "wins," which is called shadowing. Ch.8 covers this in full, once you've seen a constructor use it on purpose.

Common Pitfalls

  • Writing a getter or setter for every instance variable reflexively. Only write one when something outside the class genuinely needs to read or change that specific value — a setter in particular can undermine whatever rules the class's own methods were meant to enforce.
  • Forgetting toString and being surprised by ugly default output. If you're going to print an object for debugging or status, toString is worth the two minutes it takes to write.

Key Takeaways

  • Getters return an instance variable's value (no parameters, conventionally get... or is.../has... for a boolean); setters assign a new value (one parameter, void return).
  • Not every instance variable needs a getter or setter — only add one when something outside the class actually needs it.
  • toString is called automatically whenever Java needs to convert an object to text — write your own for useful debug output (it overrides the one every class inherits, Ch.17).
  • Method parameters follow the same call-by-value rule as before: primitives are copied.
  • Instance variables, parameters, and local variables each have their own scope (where they're visible) and lifetime (how long they exist) — a parameter or local variable can shadow an instance variable of the same name (Ch.8).

Derived from csawesome-2026: unit-3-class-creation/3.05-methods-how-to-write-them.md (CSA 3.5)