JB Header

Java Methods: Defining, Calling and Returning Values

Introduction As programs grow, putting everything in main() quickly becomes unmanageable. Methods let you give a block of code a name, and run it whenever you need it - with different inputs each time. This tutorial explains Java methods: how to define them, call them and return values from them. We will start with what a method is and why methods matter. We will then look at each part of a method declaration. Next we will pass values to methods through parameters, and get results back with return. Lastly, we will see how method calls work on the call stack, and go through guidelines for writing good methods.

(Note - The examples use static methods, which can be called directly from main(). The difference between static and instance methods is explained in Static vs Instance MethodsClick to read tutorial: Static vs Instance Methods in Java.) What is a method and why use one? A method is a named block of code which performs one task. You define it once, and call it by name as many times as you like. Methods help in several ways -
  • Reuse: write the code once, and use it from many places. A bug fixed in the method is fixed everywhere.
  • Readability: a well-named method call such as calculateTax(amount) says what happens, so readers do not have to work out how.
  • Breaking down problems: a big task becomes a series of small, simple methods, each of which can be understood and tested on its own.
You have already used many methods - System.out.println(), Math.max(), "text".length() - and written one in every program: main(). Parts of a method declaration
modifiers returnType methodName(parameterList) { body }
Where,
  • modifiers - optional keywords such as public, private and static.
  • returnType - the type of value the method gives back, such as int or String, or void if it gives back nothing.
  • methodName - by convention a verb in camelCase, such as calculateTotal or isValid.
  • parameterList - zero or more inputs, each with a type and a name, separated by commas. Empty parentheses mean no parameters.
  • body - the statements that run when the method is called.
The method's name together with its parameter types is its signature - for example calculateTotal(double, int).
Defining and calling methods
//FirstMethods.java
public class FirstMethods {
  static void printLine() {                         // no parameters, returns nothing
    System.out.println("-".repeat(30));
  }

  static void greet(String name) {                  // one parameter, returns nothing
    System.out.println("Hello, " + name + "!");
  }

  static double calculateTotal(double price, int quantity) {   // two parameters, returns a double
    return price * quantity;
  }

  public static void main(String[] args) {
    printLine();
    greet("Tom");
    greet("Harry");
    double total = calculateTotal(19.99, 3);
    System.out.println("Total: " + total);
    System.out.println("Another: " + calculateTotal(5.25, 4));
    printLine();
  }
}
 OUTPUT of the above code
------------------------------
Hello, Tom!
Hello, Harry!
Total: 59.97
Another: 21.0
------------------------------
Explanation of the code
  • A method is called by writing its name followed by the arguments in parentheses - greet("Tom"). The parentheses are needed even when there are no arguments: printLine().
  • greet() was called twice with different arguments, running the same code with a different name each time.
  • The value returned by calculateTotal() can be stored in a variable, or used directly in an expression.
  • Methods are declared inside the class, but outside other methods. The order of methods in a class does not matter.
Parameters and arguments Parameters are the variables listed in the method declaration - price and quantity. Arguments are the actual values passed in a call - 19.99 and 3. When the method is called, each parameter is initialized with the matching argument -
  • Arguments are matched to parameters by position, not by name, so their order matters.
  • There must be the same number of arguments as parameters, and each argument must be of a compatible type - a widening conversion, such as int to double, is allowed.
  • Parameters are local variables of the method. They exist only while the method runs.
Calling a method with the wrong arguments
//WrongArguments.java
public class WrongArguments {
  static double calculateTotal(double price, int quantity) {
    return price * quantity;
  }

  public static void main(String[] args) {
    calculateTotal(19.99);
    calculateTotal(3, 19.99);
  }
}
 OUTPUT on compiling the above code
WrongArguments.java:8: error: method calculateTotal in class WrongArguments cannot be applied to given types;
    calculateTotal(19.99);
    ^
  required: double,int
  found:    double
  reason: actual and formal argument lists differ in length
WrongArguments.java:9: error: incompatible types: possible lossy conversion from double to int
    calculateTotal(3, 19.99);
                      ^
Note: Some messages have been simplified; recompile with -Xdiags:verbose to get full output
2 errors
The compiler checks every call against the method's parameters - one argument is too few, and in the second call the arguments are in the wrong order, so 19.99 cannot be passed as an int. Returning values The return statement ends the method immediately and sends a value back to the caller.
  • A method with a return type other than void must return a value of that type on every path through the method - otherwise it does not compile.
  • A method can have several return statements, for example one for each case of an if. The first one reached ends the method.
  • A void method returns nothing, but can use a bare return; to end early.
  • A method returns at most one value. To return several, return an array or an object which holds them.
Returning values from methods
//ReturnValues.java
public class ReturnValues {
  static boolean isEven(int n) {
    return n % 2 == 0;
  }

  static String grade(int marks) {
    if (marks >= 75) {
      return "Distinction";
    }
    if (marks >= 40) {
      return "Pass";
    }
    return "Fail";
  }

  static double average(int[] values) {
    if (values.length == 0) {
      return 0;                               // early return for the special case
    }
    int sum = 0;
    for (int v : values) {
      sum += v;
    }
    return (double) sum / values.length;
  }

  static void printIfPositive(int n) {
    if (n <= 0) {
      return;                                 // leave a void method early
    }
    System.out.println(n + " is positive");
  }

  public static void main(String[] args) {
    System.out.println("isEven(10): " + isEven(10));
    System.out.println("grade(82): " + grade(82) + ", grade(55): " + grade(55) + ", grade(12): " + grade(12));
    System.out.println("average: " + average(new int[] {70, 85, 90}));
    System.out.println("average of nothing: " + average(new int[0]));
    printIfPositive(5);
    printIfPositive(-3);
    System.out.println("Nested calls: " + Math.max(isEven(4) ? 10 : 1, Math.max(7, 3)));
  }
}
 OUTPUT of the above code
isEven(10): true
grade(82): Distinction, grade(55): Pass, grade(12): Fail
average: 81.66666666666667
average of nothing: 0.0
5 is positive
Nested calls: 10
Explanation of the code
  • isEven() returns the result of a comparison directly - there is no need for if (...) return true; else return false;.
  • grade() returns as soon as a condition matches, using the guard clause style from if-else statementsClick to read tutorial: Java if, else if and else Statements with Examples.
  • printIfPositive(-3) printed nothing, because the bare return; left the method early.
  • Method calls can be used anywhere a value of their return type can - even as arguments to other method calls, as in the last line.
How method calls work - the call stack When a method is called, Java pauses the caller, creates a new stack frame to hold the called method's parameters and local variables, and runs the method. When it returns, its frame is removed and the caller continues exactly where it paused, with the returned value. Because each call has its own frame, methods can call other methods - and even themselves, as in recursionClick to read tutorial: Recursion in Java with Examples.
Following calls through the call stack
//CallStack.java
public class CallStack {
  static int square(int x) {
    System.out.println("    square(" + x + ") called");
    int result = x * x;
    System.out.println("    square(" + x + ") returns " + result);
    return result;
  }

  static int sumOfSquares(int a, int b) {
    System.out.println("  sumOfSquares(" + a + ", " + b + ") called");
    int result = square(a) + square(b);
    System.out.println("  sumOfSquares returns " + result);
    return result;
  }

  public static void main(String[] args) {
    System.out.println("main() calls sumOfSquares");
    int answer = sumOfSquares(3, 4);
    System.out.println("main() received " + answer);
  }
}
 OUTPUT of the above code
main() calls sumOfSquares
  sumOfSquares(3, 4) called
    square(3) called
    square(3) returns 9
    square(4) called
    square(4) returns 16
  sumOfSquares returns 25
main() received 25
main() waited while sumOfSquares() ran, which in turn waited while each square() call ran. The local variable result in each method is separate - they live in different frames. When an exception occurs, the stack trace Java prints is exactly this chain of frames. Guidelines for writing good methods
  • Do one thing: a method should have a single, clear purpose. If its name needs "and", consider splitting it.
  • Name it after what it does: calculateTax(), isValidEmail(), printReport(). Methods returning a boolean usually start with is, has or can.
  • Keep it short: if a method no longer fits on a screen, it probably does more than one thing.
  • Few parameters: more than three or four parameters are hard to pass in the right order. Group related values into an object.
  • Prefer returning results to printing them: a method which returns a value can be reused and tested; one which only prints cannot.
Summary In this tutorial we first saw what a method is, and why methods make code reusable, readable and easier to break down. We then went through the parts of a method declaration - modifiers, return type, name, parameters and body - and defined and called methods. Next we passed arguments to parameters by position, and saw the compiler check every call. We then returned values with return, including early returns and bare return; in void methods. Lastly, we followed calls through the call stack, and went through guidelines for good methods. In the next tutorial, we will answer a famous question: is Java pass-by-value or pass-by-reference?Click to read tutorial: Is Java Pass-by-Value or Pass-by-Reference?