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
ifor 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
toStringand being surprised by ugly default output. If you're going to print an object for debugging or status,toStringis worth the two minutes it takes to write.
Key Takeaways
- Getters return an instance variable's value (no parameters, conventionally
get...oris.../has...for aboolean); setters assign a new value (one parameter,voidreturn). - Not every instance variable needs a getter or setter — only add one when something outside the class actually needs it.
toStringis 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)