3.5 - Methods: How to Write Them
A void method doesn’t return anything, its header has
void right before the method name.A non-void method returns exactly one value, and its header shows the actual return type instead of
void.public void printName() { // void, no return System.out.println(name); } public int getAge() { // non-void, returns an int return age; }
In a non-void method, whatever expression follows
return gets evaluated and sent back to whoever called the method, this is called return by value.The return expression has to be compatible with the return type: either the same type, or a type Java converts automatically. An
int can be returned from a double method, but a double can’t be returned from an int method without a cast.public double getHalfAge() { return age / 2.0; // double expression, double return type } public double getAgeAsDouble() { return age; // fine: the int is converted to a double (3 becomes 3.0) } public int getAgeInMonths() { return age * 12.0; // compile error: a double can't be returned from an int method }
The
return keyword sends control back to wherever the method was called from. Anything written after a return statement never runs. If return shows up inside an if or a loop, it immediately exits the method right then and there, skipping whatever else was left in that block.public int checkAge(int age) { if (age < 0) { return -1; // exits immediately, nothing after this runs for this case } return age; }
A
return inside a loop works the same way: the loop stops, and the method ends right there.// Returns true if n has a factor between 2 and n - 1 public boolean hasFactor(int n) { for (int i = 2; i < n; i++) { if (n % i == 0) { return true; // ends the loop and the method immediately } } return false; // only reached if the loop finishes without finding a factor } hasFactor(15); // true: the loop stops at i = 3 and never checks 4 through 14 hasFactor(7); // false: the loop checks 2 through 6, then the last line runs
A
void method can use return; with no value to stop early, and so can a constructor. Also, Java won’t even compile a statement written directly after a return in the same block, since it could never run.An accessor method (sometimes called a getter) lets other classes grab a copy of an instance variable or class variable’s value. Accessor methods are always non-void.
public String getName() { // accessor / getter return name; }
Since it’s a copy, changing the returned value doesn’t change the object:
int a = myDog.getAge(); // a gets a copy of the dog's age, say 3 a = 10; // only a changes, myDog's age is still 3
A mutator method (also called a modifier, or a setter) changes the value of an instance variable or class variable. These are usually void.
public void setName(String newName) { // mutator / setter name = newName; }
Mutators don’t have to just copy in a new value. They can update a value based on the old one, or check a new value before accepting it:
public void haveBirthday() { // mutator: changes age based on its current value age++; } public void setAge(int newAge) { if (newAge >= 0) { // only accepts ages that make sense age = newAge; } }
When a method has parameters, it uses those parameter values to do its job. If the argument passed in is a primitive value, the parameter just gets a copy of that value, so any changes made to the parameter inside the method never affect the original variable back where the method was called.
public void doubleIt(int x) { x = x * 2; // only changes the local copy } int num = 5; doubleIt(num); System.out.println(num); // still 5, the original was never touched
Here’s a full class and the result of calling its methods. Tracing code like this is a common multiple choice question:
public class Dog { private String name; private int age; public Dog(String n, int a) { name = n; age = a; } public int getAge() { return age; } public void haveBirthday() { age++; } public void setAge(int newAge) { if (newAge >= 0) { age = newAge; } } public int humanYears() { return age * 7; } }
Dog rex = new Dog("Rex", 3); rex.haveBirthday(); System.out.println(rex.getAge()); // 4 rex.setAge(-2); // ignored, since -2 fails the check System.out.println(rex.getAge()); // 4 System.out.println(rex.humanYears()); // 28 int x = 6; rex.setAge(x); // the parameter newAge gets a copy of x x = 1; // changing x now has no effect on rex System.out.println(rex.getAge()); // 6