Methods

Paul Ngugi - May 10 - - Dev Community

Methods can be used to define reusable code and organize and simplify coding. Suppose that you need to find the sum of integers from 1 to 10, from 20 to 37, and from 35 to 49, respectively. You may write the code as follows:

int sum = 0;
for (int i = 1; i <= 10; i++)
 sum += i;
System.out.println("Sum from 1 to 10 is " + sum);
sum = 0;
for (int i = 20; i <= 37; i++)
 sum += i;
System.out.println("Sum from 20 to 37 is " + sum);
sum = 0;
for (int i = 35; i <= 49; i++)
 sum += i;
System.out.println("Sum from 35 to 49 is " + sum);
Enter fullscreen mode Exit fullscreen mode

You may have observed that computing these sums from 1 to 10, from 20 to 37, and from 35 to 49 are very similar except that the starting and ending integers are different. Wouldn’t it be nice if we could write the common code once and reuse it? We can do so by defining a method and invoking it.

The preceding code can be simplified as follows:

Image description

Lines 5-11 define the method named sum with two parameters i1 and i2. The statements in the main method invoke sum(1, 10) to compute the sum from 1 to 10, sum(20, 37) to compute the sum from 20 to 37, and sum(35, 49) to compute the sum from 35 to 49.

A method is a collection of statements grouped together to perform an operation. In earlier chapters you have used predefined methods such as System.out.println, System.exit, Math.pow, and Math.random. These methods are defined in the Java library.

Defining a Method

A method definition consists of its method name, parameters, return value type, and body.

The syntax for defining a method is as follows:

modifier returnValueType methodName(list of parameters) {
 // Method body;
}
Enter fullscreen mode Exit fullscreen mode

Let’s look at a method defined to find the larger between two integers. This method, named max, has two int parameters, num1 and num2, the larger of which is returned by the method. Below, illustrates the components of this method.

Image description

The method header specifies the modifiers, return value type, method name, and parameters of the method. The static modifier is used for all the methods here.

A method may return a value. The returnValueType is the data type of the value the method returns. Some methods perform desired operations without returning a value. In this case, the returnValueType is the keyword void. For example, the returnValueType is void in the main method, as well as in System.exit, and System.out.println. If a method returns a value, it is called a value-returning method; otherwise it is called a void method.

The variables defined in the method header are known as formal parameters or simply parameters. A parameter is like a placeholder: when a method is invoked, you pass a value to the parameter. This value is referred to as an actual parameter or argument. The parameter list refers to the method’s type, order, and number of the parameters. The method name and the parameter list together constitute the method signature. Parameters are optional; that is, a method may contain no parameters. For example, the Math.random() method has no parameters.

The method body contains a collection of statements that implement the method. The method body of the max method uses an if statement to determine which number is larger and return the value of that number. In order for a value-returning method to return a result, a return statement using the keyword return is required. The method terminates when a return statement is executed.

Some programming languages refer to methods as procedures and functions. In those languages, a value-returning method is called a function and a void method is called a procedure.

In the method header, you need to declare each parameter separately. For instance, max(int num1, int num2) is correct, but max(int num1, num2) is wrong.

We say “define a method” and “declare a variable.” We are making a subtle distinction here. A definition defines what the defined item is, but a declaration usually involves allocating memory to store data for the declared item.

Calling a Method

Calling a method executes the code in the method. In a method definition, you define what the method is to do. To execute the method, you have to call or invoke it. There are two ways to call a method, depending on whether the method returns a value or not.

If a method returns a value, a call to the method is usually treated as a value. For example,

int larger = max(3, 4);
Enter fullscreen mode Exit fullscreen mode

calls max(3, 4) and assigns the result of the method to the variable larger. Another example of a call that is treated as a value is

System.out.println(max(3, 4));
Enter fullscreen mode Exit fullscreen mode

which prints the return value of the method call max(3, 4).

If a method returns void, a call to the method must be a statement. For example, the method println returns void. The following call is a statement:

System.out.println("Welcome to Java!");
Enter fullscreen mode Exit fullscreen mode

A value-returning method can also be invoked as a statement in Java. In this case, the caller simply ignores the return value. This is not often done, but it is permissible if the caller is not interested in the return value.

When a program calls a method, program control is transferred to the called method. A called method returns control to the caller when its return statement is executed or when its method-ending closing brace is reached.
The complete program is used to test the max method:

Image description

This program contains the main method and the max method. The main method is just like any other method except that it is invoked by the JVM to start the program.

The main method’s header is always the same. Like the one in this example, it includes the modifiers public and static, return value type void, method name main, and a parameter of the String[] type. String[] indicates that the parameter is an array of String.

The statements in main may invoke other methods that are defined in the class that contains the main method or in other classes. In this example, the main method invokes max(i, j), which is defined in the same class with the main method.

When the max method is invoked (line 8), variable i’s value 5 is passed to num1, and variable j’s value 2 is passed to num2 in the max method. The flow of control transfers to the max method, and the max method is executed. When the return statement in the max method is executed, the max method returns the control to its caller (in this case the caller is the main method). This process is illustrated in below:

Image description

When the max method is invoked, the flow of control transfers to it. Once the max method is finished, it returns control back to the caller.

A return statement is required for a value-returning method. The method shown below in (a) is logically correct, but it has a compile error because the Java compiler thinks that this method might not return a value.

Image description

To fix this problem, delete if (n < 0) in (a), so the compiler will see a return statement to be reached regardless of how the if statement is evaluated.

Methods enable code sharing and reuse. The max method can be invoked from any class, not just TestMax. If you create a new class, you can invoke the max method using ClassName.methodName (i.e., TestMax.max).

Each time a method is invoked, the system creates an activation record (also called an activation frame) that stores parameters and variables for the method and places the activation record in an area of memory known as a call stack. A call stack is also known as an execution stack, runtime stack, or machine stack, and it is often shortened to just “the stack.” When a method calls another method, the caller’s activation record is kept intact, and a new activation record is created for the new method called. When a method finishes its work and returns to its caller, its activation record is removed from the call stack.

A call stack stores the activation records in a last-in, first-out fashion: The activation record for the method that is invoked last is removed first from the stack. For example, suppose method m1 calls method m2, and m2 calls method m3. The runtime system pushes m1’s activation record into the stack, then m2’s, and then m3’s. After m3 is finished, its activation record is removed from the stack. After m2 is finished, its activation record is removed from the stack. After m1 is finished, its activation record is removed from the stack.

Understanding call stacks helps you to comprehend how methods are invoked. The variables defined in the main method are i, j, and k. The variables defined in the max method are num1, num2, and result. The variables num1 and num2 are defined in the method signature and are parameters of the max method. Their values are passed through method invocation. Below, illustrates the activation records for method calls in the stack.

Image description

When the max method is invoked, the flow of control transfers to the max method. Once the max method is finished, it returns control back to the caller.

void Method Example

A void method does not return a value.

The preceding section gives an example of a value-returning method. This section shows how to define and invoke a void method. The program defines a method named printGrade and invokes it to print the grade for a given score.

Image description

The printGrade method is a void method because it does not return any value. A call to a void method must be a statement. Therefore, it is invoked as a statement in line 4 in the main method. Like any Java statement, it is terminated with a semicolon.

To see the differences between a void and value-returning method, let’s redesign the printGrade method to return a value. The new method, which we call getGrade, returns the grade as shown below:

Image description

The getGrade method defined in lines 10-21 returns a character grade based on the numeric score value. The caller invokes this method in lines 6-7.

The getGrade method can be invoked by a caller wherever a character may appear. The printGrade method does not return any value, so it must be invoked as a statement.

A return statement is not needed for a void method, but it can be used for terminating the method and returning to the method’s caller. The syntax is simply

return;

This is not often done, but sometimes it is useful for circumventing the normal flow of control in a void method. For example, the following code has a return statement to terminate the method when the score is invalid.

public static void printGrade(double score) {
if (score < 0 || score > 100) {
 System.out.println("Invalid score");
return;
 }
if (score >= 90.0) {
 System.out.println('A');
 }
else if (score >= 80.0) {
 System.out.println('B');
 }
else if (score >= 70.0) {
 System.out.println('C');
 }
else if (score >= 60.0) {
 System.out.println('D');
 }
else {
 System.out.println('F');
 }
}
Enter fullscreen mode Exit fullscreen mode

Passing Arguments by Values

The arguments are passed by value to parameters when invoking a method. The power of a method is its ability to work with parameters. You can use println to print any string and max to find the maximum of any two int values. When calling a method, you need to provide arguments, which must be given in the same order as their respective parameters in the method signature. This is known as parameter order association. For example, the following method prints a message n times:

public static void nPrintln(String message, int n) {
for (int i = 0; i < n; i++)
 System.out.println(message);
}
Enter fullscreen mode Exit fullscreen mode

You can use nPrintln("Hello", 3) to print Hello three times. The nPrintln("Hello", 3) statement passes the actual string parameter Hello to the parameter message, passes 3 to n, and prints Hello three times. However, the statement nPrintln(3, "Hello") would be wrong. The data type of 3 does not match the data type for the first parameter, message, nor does the second argument, Hello, match the second parameter, n.

The arguments must match the parameters in order, number, and compatible type, as defined in the method signature. Compatible type means that you can pass an argument to a parameter without explicit casting, such as passing an int value argument to a double value parameter.

When you invoke a method with an argument, the value of the argument is passed to the parameter. This is referred to as pass-by-value. If the argument is a variable rather than a literal value, the value of the variable is passed to the parameter. The variable is not affected, regardless of the changes made to the parameter inside the method. As shown below, the value of x (1) is passed to the parameter n to invoke the increment method (line 8). The parameter n is incremented by 1 in the method (line 13), but x is not changed no matter what the method does.

Image description

Here's another program that demonstrates the effect of passing by value. The program creates a method for swapping two variables. The swap method is invoked by passing two arguments. Interestingly, the values of the arguments are not changed after the method is invoked.

package demo;

public class TestPassByValue {

    public static void main(String[] args) {
        // Declare and initialize variables
        int num1 = 1;
        int num2 = 2;

        System.out.println("Before invoing the swap method, num1 is " + num1 + " and num2 is " + num2);

        // Invoke the swap method to attempt to swap two variables
        swap(num1, num2);

        System.out.println("After invoking the swap method, num1 is " + num1 + " and num2 is " + num2);
    }

    /** Swap two variables */
    public static void swap(int n1, int n2) {
        System.out.println("\tInside the swap method");
        System.out.println("\t\tBefore swapping, n1 is " + n1 + " and n2 is " + n2);

        // Swap n1 with n2
        int temp = n1;
        n1 = n2;
        n2 = temp;

        System.out.println("\t\tAfter swappin, n1 is " + n1 + " and n2 is " + n2);
    }

}

Enter fullscreen mode Exit fullscreen mode

Before the swap method is invoked (line 13), num1 is 1 and num2 is 2. After the swap method is invoked, num1 is still 1 and num2 is still 2. Their values have not been swapped. As shown below, the values of the arguments num1 and num2 are passed to n1 and n2, but n1 and n2 have their own memory locations independent of num1 and num2. Therefore, changes in n1 and n2 do not affect the contents of num1 and num2.

Another twist is to change the parameter name n1 in swap to num1. What effect does this have? No change occurs, because it makes no difference whether the parameter and the argument have the same name. The parameter is a variable in the method with its own memory space. The variable is allocated when the method is invoked, and it disappears when the method is returned to its caller.

Image description

For simplicity, Java programmers often say passing x to y, which actually means passing the value of argument x to parameter y.

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .