Java from the ground up

Methods: parameters and return values

Naming a piece of work, handing it values, getting an answer back, and why every method so far has been marked static.

Part 6 of 12

Intermediate15 min readBack to Courses

A name for a piece of work

A method is a block of code with a name, so you can call it by that name instead of copying the lines. The header says what goes in and what comes out: static int add(int a, int b) takes two whole numbers and hands back a whole number.

The values you hand in are the parameters, and they exist only inside the method. From the caller you pass arguments — add(2, 3) — and Java copies them in. Changing a parameter inside the method cannot change the caller value, which keeps the two sides separate.

Return values, and methods that return nothing

A return statement ends the method and hands the value back to whoever called it. The type in the header must match what is returned, and the compiler checks every path through the method: if a branch ends without returning, the file will not compile.

When a method only does something — prints a line, changes a value — it returns nothing, and that is written as void. The difference is easy to feel: a method that returns a value can be used inside a calculation, a void one has to stand on its own line.

Why static, for now

Every method here is marked static, and so is main. A static method belongs to the class itself rather than to any object, so you can call it without first building anything. That is precisely what main needs, and it keeps these first chapters free of objects.

Chapter nine changes this on purpose. Once a class holds data of its own, the methods that work on that data stop being static and become part of the object — the same shape, with one word removed. The reason for the change is easier to see when reading a real class.

The call stack

When one method calls another, Java keeps a frame for each call: the parameters, the local variables, and where to return. The frames stack up, which is why an error trace reads like a list of calls. When a method returns, its frame is discarded and the caller continues.

That is also why a parameter cannot leak back to the caller. The method receives a copy of the value, works in its own frame, and hands back only what it returns. Arrays and objects are different: the copy is a reference, so their contents can be changed.

Overloading, and one job per method

Two methods may share a name when their parameter lists differ. add(int, int) and add(double, double) are different methods, and the compiler picks one from the argument types. The return type alone is not enough to tell them apart.

A good method answers one question. If the name needs the word and, split it. If it returns a value and also prints, decide which job it has; a method that prints is hard to test, and a method that returns is easy to use in the next calculation.

A method that calls itself

A method may call itself, and for some problems that is the shortest way to say what you mean. The rule is to reduce the input on every call and to write a case that stops. factorial(0) answers 1, and factorial(n) answers n * factorial(n - 1); each call is smaller, so the stack of frames has a bottom.

Recursion is not a shortcut around the call stack, it is a use of it. Each waiting call keeps its frame until the smaller call returns, so a recursion that goes ten thousand deep uses ten thousand frames and can overflow the stack. When the input can be that large, a loop is the safer shape. For a tree, a nested list or a file path, recursion usually is the clearer one.

A void method, a returning method, and one using both

static void line(String text) {
    System.out.println("-- " + text);
}

static int doubleIt(int value) {
    return value * 2;
}

static int total(int[] numbers) {
    int sum = 0;
    for (int number : numbers) sum += number;
    return sum;
}

// Called from main, in order:
line("Numbers");
System.out.println(doubleIt(21));
System.out.println("total = " + total(new int[] {1, 2, 3}));

Three methods and a main

Press Run and read the output. Then write a method of your own that takes a whole number and returns it doubled, call it from main, and print the answer.

Output
Click "Run" to execute your code

Three method mistakes: a branch that returns nothing in a method declared to return a value, arguments in the wrong order when both have the same type, and calling an instance method from static main without an object. The first stops compilation; the second can compile and quietly compute the wrong answer.

Try these next

  • Write max(int, int) and max(int, int, int), then call both from main.
  • Write a method that returns the average of an int[], and a void method that prints a label above it.
  • Change a parameter inside a method and print it in the caller afterward; explain why the caller sees the old value.

A converter with two overloads

Press Run and match each line to the method that returned it. Then add a `toKelvin` method, call it from main, and check one value by hand.

Output
Click "Run" to execute your code

Give a method a name that says what it answers — average, greet, add — and keep it short enough to check by reading. A method that needs the word and in its name is usually two methods.

Check what you learned

One question at a time. A wrong answer explains itself — take another go.

Part 1 of 5

What does a method marked void return?