JAVA / METHODS
Parameters, arguments and return values
Write methods that take typed parameters, call them with arguments bound by position, and use the value they return inside larger expressions.
What you will learn
- Tell parameters (in the signature) apart from arguments (at the call site)
- Match arguments to parameters by position and type, never by variable name
- Use the returned value in an expression instead of printing from inside the method
- Give every path of a value-returning method a return, and know return ends the call
Understanding Parameters, arguments and return values
A parameter is a variable declared in the method's signature; an argument is the value you hand over when you call. Each call creates fresh parameter variables and initializes them from the arguments, matched strictly left to right by position, so area(w, h) and area(h, w) are different calls even when both variables are ints. The parameter names are private to the body: renaming width to w inside area changes nothing for any caller, which is exactly why a method can be reused from code that knows nothing about it.
The return type is the promise the method makes about what its call evaluates to. A return statement does two separate things: it supplies that value and it ends the method immediately, skipping every statement after it, including the rest of an enclosing loop. Because a call is an expression of the declared return type, you can drop it anywhere a value of that type fits: assign it, add it to a number, or pass it straight in as another method's argument. A void method makes no such promise, so its call is a statement only and int x = print(...) will not compile.
The compiler checks both ends of the deal. At the call site it counts the arguments and checks that each one is assignable to its parameter, silently widening an int to a double but refusing to narrow a double to an int without a cast. Inside the body it insists that every path reaches a return, because a caller that received nothing would have no value for the expression to produce. What it never checks is whether you use the result: writing area(3, 4); on its own line runs the body and throws the answer away.
public class MethodValues {
// width and height are parameters: fresh local variables created on every call
static int area(int width, int height) {
return width * height;
}
static double halfOf(double value) {
return value / 2;
}
// void: the call produces no value, so it can only be used as a statement
static void print(String label, double number) {
System.out.println(label + " = " + number);
}
public static void main(String[] args) {
int w = 3;
int h = 7;
int a = area(w, h); // w and h are the arguments, bound by position
System.out.println("a = " + a);
// a call is an expression of its return type, so calls can feed other calls
System.out.println("nested = " + area(area(2, 3), 4));
print("half", halfOf(5)); // the int 5 widens to the double parameter
area(w, h); // legal statement; the returned int is discarded
}
}A method call is an expression: argument values are copied into freshly created parameters by position, the body runs, and the call evaluates to whatever return hands back.
Worked examples
Every path needs a return
A value-returning method must hand back a value on all paths, and the first return that runs ends the call.
public class Grade {
static String letter(int score) {
if (score >= 90) {
return "A";
}
if (score >= 80) {
return "B";
}
return "C";
}
public static void main(String[] args) {
System.out.println(letter(95));
System.out.println(letter(83));
System.out.println(letter(12));
}
}Example explained
Line 1letter(95) reaches the first return, so the method ends there and the second if is never evaluated.
Line 2The final return "C" is not optional: without it a score of 12 would fall off the end of a method that promised a String, and the compiler reports 'missing return statement'.
Line 3No else is needed anywhere, because return already leaves the method.
Line 4Each call evaluates to a String, which is why it can be used directly as the argument to println.
Arguments are values, computed first
Argument expressions are evaluated left to right before the body begins, and only their values reach the parameters.
public class ArgOrder {
static int loud(String name, int value) {
System.out.println("evaluating " + name);
return value;
}
static void show(int a, int b) {
System.out.println("a=" + a + ", b=" + b);
}
public static void main(String[] args) {
show(loud("left", 10), loud("right", 20));
}
}Example explained
Line 1Both argument expressions run to completion before show starts, which is why the two evaluating lines print first.
Line 2They are evaluated left to right, so left always prints before right.
Line 3The parameters a and b receive the numbers 10 and 20, not the calls that produced them, so show cannot tell where they came from.
Important notes
Widening at the call is automatic (int to long or double), narrowing is not: passing a double to an int parameter is a compile error until you add a cast, and that cast drops the fractional part.
A return inside a loop leaves the whole method, not just the loop; use break when you only want to stop looping.
Common mistakes
Printing the answer inside a void method instead of returning it: the caller can never reuse or format it, and int a = area(3, 4); fails with 'void cannot be converted to int'.
Assuming arguments bind by name, so calling minutesBetween(end, start) because the local variables happen to be named end and start; both are ints, so it compiles and returns a wrong number with no warning.
Putting returns only inside if branches with nothing after them: the method is rejected with 'missing return statement' because one path would end without producing a value.
Try it yourself
Change, predict, then run
Write static int clamp(int value, int low, int high) that returns low when value is below low, high when value is above high, and value otherwise. Then print clamp(5, 1, 10), clamp(-3, 1, 10) and clamp(42, 1, 10) on separate lines.
Open the Java workspaceCheck your understanding
A method static int add(int a, int b) prints the word adding and then returns a + b. What happens when a caller writes add(1, 2); as a statement on its own, ignoring the result?
- The body runs, adding is printed, and the returned 3 is discarded
- It does not compile, because the returned int is not assigned to anything
- The body runs and prints adding followed by 3
- Nothing happens, because a return value nobody stores means the call is skipped
Show answer
A method invocation is allowed to stand alone as a statement, so the body executes normally and the value it returns is simply dropped. The compile-error option is tempting because Java is strict about types, but that strictness applies where a value is used; nothing forces a caller to consume one. And 3 is never printed unless the caller prints it, since the method only prints the word adding.