Chapter 9.J

Java Methods

Methods in Java

Subsections of Java Methods

Methods

YouTube Video

Video Materials

Now that we’ve covered the basic ideas of adding methods to our programs, let’s see how we can do that using the Java programming language.

Declaring Methods

We’ve already seen how to create methods in our programs, since each program in Java already includes a method named main. In general, a method declaration in Java needs a few elements. Let’s start at the simplest case:

public static void foo(){
    System.out.println("Foo");
    return;
}

Let’s break this example method declaration down to see how it works:

  1. First, we use the keyword static at the beginning of this method declaration. That keyword allows us to use this method without creating an object first. We’ll cover how to create and work with objects in a later module. For now, each method we create will need the static keyword in front of it, just like the main() method.
  2. Then, the second keyword, void, determines the type of data returned by the method. We use a special keyword void when the method does not return a value. We’ve already seen this keyword used in our declaration of the main method.
  3. Next, we have the name of the method, foo. We can name a method using any valid identifier in Java. In general, method names in Java always start with a lowercase letter.
  4. Following the method name, we see a set of parentheses () that list the parameters for this method. Since there is nothing included in this example, the method foo does not require any parameters.
  5. Finally, we see a set of curly braces {} that surround the code of the method itself. In this case, the method will simply print Foo to the terminal.
  6. The method ends with the return keyword. Since we aren’t returning a value, we aren’t required to include a return keyword in the method. However, it is helpful to know that we may use that keyword to exit the method at any time.

We’ll cover how to handle method parameters and return values later in this module. For now, we’ll just look at creating simple methods that neither require parameters nor return values.

Calling Methods

Once we’ve created a method in our code, we can call, or execute, the method from anywhere in our code using the following syntax:

foo();

We simply use the name of the method, followed by parentheses, wherever we’d like to call that method. Again, we’ll see how to pass arguments to the method and store the return value later in this module.

Example

Let’s look at a complete sample program to see how this all fits together.

public class Methods{
    public static void main(String[] args){
        System.out.println("Main 1");
        foo();
        System.out.println("Main 2");
        foo();
        System.out.println("Main 3");
        return;
    }
  
    public static void foo(){
        System.out.println("Foo 1");
        return;
    }
}

When we run this program, we should see the following output:

Main 1
Foo 1
Main 2
Foo 1
Main 3

We can also look at a flowchart diagram of this program to help understand how it works:

Method Call Flowchart Method Call Flowchart

As we can see in this diagram, the program starts in the main() method. Inside, it prints Main 1, then calls the method foo(). So, we can follow the dashed line over to foo(), where it will print Foo 1 and return back to main along the same dashed line. Then, we’ll print Main 2 in main(), before calling foo() once again. This time, we’ll follow the dotted line to foo(), where we’ll once again print Foo 1 before returning back to main() and printing Main 3.

Method Signature

The line public static void main(String[] args) is often referred to as a method signature. It contains all the vital information necessary to use the method: its name, what it returns, and what type of parameters it requires. Even public static inform the programmer on where and how to invoke the method, but we’ll cover these key words when we cover classes.

Subsections of Methods

Parameters

YouTube Video

Video Materials

Methods are a very useful way to divide our code into smaller chunks. However, many times we need to provide input to our methods. This allows us to reuse the same code, but with different values each time we call the method. So, let’s review how to add parameters to our methods in Java.

Method Parameters

In Java, we can add parameters to a method declaration by placing them in the parentheses () at the end of the declaration. Each parameter is similar to a variable declaration, requiring both a type and an identifier. We can also define multiple parameters, separated by commas ,.

For example, let’s extend our definition of foo() from the previous page by adding a String parameter named message:

static void foo(String message){
    System.out.println("Message: " + message);
}

Then, when we call that method, we are required to provide an argument of the correct type. That argument will be stored as the parameter’s variable in foo():

foo("Hello World!");

Another Example

Here’s another example. In this case, we are writing two methods, foo() and bar(). They accept multiple parameters, and in main() we call each method using arguments for each parameter.

public class Parameters{
    public static void main(String[] args){
        int x = 5;
        int y = 10;
        int z = 8;
        bar(x, y, z);
        foo(y, true);
    }
  
    static void foo(int output, boolean longMessage){
        if(longMessage){
            System.out.println("The value was " + output);
        }else{
            System.out.println("Val: " + output);
        }
    }
  
    static void bar(int a, int b, int c){
        System.out.println(a + ", " + b + ", " + c);
    }
}

First, let’s look at bar(). When we call this method from main(), we are using x, y, and z as arguments. So, inside of bar(), the value stored in x will be stored in a, y will be stored in b, and z will be stored in c. The parameters and arguments are matched up based on the order they are provided to the method call. So, bar() will output 5, 10, 8 when it is called with those parameters.

The call to foo() is very similar. It only contains two parameters, but each one is a different type. So, when we call that method, we must make sure that the first parameter is an integer, and the second one is a Boolean value.

Subsections of Parameters

Overloading

YouTube Video

Video Materials

There are several other things we can do with parameters in our methods, allowing us to use them in new and more flexible ways.

Method Overloading

Java allows us to create multiple methods using the same name, or identifier in the same scope, as long as they have different parameter lists. This could include a different number of parameters, different data types for each parameter, or a different ordering of types. The names of the parameters, however, does not matter here. This is called method overloading.

For example, we could create a method named max() that could take either two or three parameters:

public class Overloading{
    public static void main(String[] args){
        max(2, 3);
        max(3, 4, 5);
    }
  
    static void max(int x, int y){
        if(x >= y){
            System.out.println(x);
        }else{
            System.out.println(y);
        }
    }
  
    static void max(int x, int y, int z){
        if(x >= y){
            if(x >= z){
                System.out.println(x);
            }else{
                System.out.println(z);
            }
        }else{
            if(y >= z){
                System.out.println(y);
            }else{
                System.out.println(z);
            }
        }
    }
}

In this example, we have two methods named max(), one that requires two parameters, and another that requires three. When Java sees a method call to max() elsewhere in the code, it will look at the number and types of arguments provided, and use that information to determine which version of max() it should use.

Of course, we could just use the three argument version of max() in both cases:

public class Overloading{
    public static void main(String[] args){
        max(2, 3);
        max(3, 4, 5);
    }
  
    static void max(int x, int y){
        max(x, y, y);
    }
  
    static void max(int x, int y, int z){
        if(x >= y){
            if(x >= z){
                System.out.println(x);
            }else{
                System.out.println(z);
            }
        }else{
            if(y >= z){
                System.out.println(y);
            }else{
                System.out.println(z);
            }
        }
    }
}

In this case, we are calling the three parameter version of max() from within the two parameter version. In effect, this allows us to define default parameters for methods such as this. If we only provide two arguments, the code will automatically call the three parameter version, filling in the third argument for us.

Variable Length Parameters

Finally, Java allows us to define a single parameter that is a variable length parameter. In essence, it will allow us to accept anywhere from 0 to many arguments for that single parameter, which will then be stored in an array. Let’s look at an example:

public class Overloading{
    public static void main(String[] args){
        max(2, 3);
        max(3, 4, 5);
        max(5, 6, 7, 8);
        max(10, 11, 12, 13, 14, 15, 16);
    }
  
    static void max(int ... values){
        if(values.length > 0){
            int max = values[0];
            for(int i : values){
                if(i > max){
                    max = i;
                }
            }
            System.out.println(max);
        }
    }
}

Here, we have defined a method named max() that accepts a single variable length parameter. To show a parameter is variable length we use three periods ... between the type and the variable name. We must respect three rules when creating a variable length parameter:

  1. Each method may only have one variable length parameter
  2. It must be the last parameter declared in the method declaration
  3. Each argument provided to the variable length parameter must be the same type

So, when we run this program, we see that we can call the max() method with any number of integer arguments, and it will be able to determine the maximum of those values. Inside of the method itself, values can be treated just like an array of integers.

Subsections of Overloading

Return

YouTube Video

Video Materials

Lastly, one of the most useful things we can do with methods in our code is return a value from a method. This allows us to use a method to perform an action or calculation that results in a single value that we can use elsewhere in our code. We can even use these method calls just like we use variables in other arithmetic expressions. Let’s take a look at how that works.

Returning a Value

To return a value from a method in Java, we use the special keyword return, followed by an expression representing the value we’d like to return. We must also declare the type of that value in our method declaration, taking the place of the void keyword we’ve been using up to this point.

Here’s an example program showing how to use the return keyword and store that returned value in a variable.

public class Return{
    public static void main(String[] args){
        int returnValue = last(1, 3, 5, 7, 9);
        System.out.println(returnValue);  // 9
    }
  
    static int last(int ... items){
        if(items.length > 0){
            return items[items.length - 1];
        }
        return -1;
    }
}

Let’s review this program carefully to see what parts of the program are important for returning a value:

  1. First, instead of void, we use the keyword int in the declaration of our last() method, static int last(int ... items). This is because the method must return a value with the type int.
  2. Inside of the method, we see two instances of the return keyword. Each instance is followed by a value or expression that results in an integer, which is then returned from the method. As soon as the method reaches a return keyword, it immediately stops executing and returns that value. So, if the items variable length parameter is empty, the method will return $-1$. Otherwise, it will return the last item in the items parameter.
  3. In the main() method, we see that we’ve included the method call to last() on the right-hand side of a variable assignment statement. So, once we reach that line of code, the program will call the last() method and store the returned value in the returnValue variable in main()

Compiler Messages

The Java compiler is a very crucial part of making sure that each method we create returns a value correctly. When we compile our code, the compiler checks to make sure that each method that includes a return type other than void will return a value along all code paths. That means that if one branch of an If-Else statement returns a value, then either the other branch or code below it should also return a value.

In addition, it will make sure that the type of the value returned matches the type that is expected by the method’s declaration.

Finally, just like every other variable assignment in Java, when we store the result of a method call in a variable, Java will also make sure that the variable storing the value has a type that is compatible with the type being returned from the method.

So, if we receive error messages from the Java compiler regarding invalid return types or values in our methods, we’ll need to carefully check our code to make sure we aren’t violating one of those rules.

Subsections of Return

A Worked Example

Video Materials

Let’s try one more example to get some practice building code that contains multiple methods. This program will convert volumes measured in U.S. standard cups into either fluid ounces, tablespoons, or teaspoons. A program that makes these conversions is useful for anyone cooking or baking.

Problem Statement1

For this example, we’ll need to build a program that matches this problem statement:

Write a program that accepts interactive keyboard input. It should first ask the user to enter a number of cups, and then have the user select the desired conversion from a list of options. The program will then calculate the correct value and display it with the correct units.

The program should contain one class named Converter, but may contain several methods.

Please enter the number of cups to convert as a floating-point value: .5
Select conversion: 1 (ounces), 2 (tablespoons) or 3 (teaspoons): 3
24.0 teaspoons

That seems like a pretty straightforward problem statement. Let’s see how we might structure the program.

Methods

First, we could look at the problem statement and try to divide the program into a number of methods to perform each action. In this case, it looks like we have a few important actions that could be made into methods:

  1. Getting the user input
  2. Performing the conversion
  3. Printing the converted value and units

Based on that breakdown, we can structure the class so it has the following methods:

  • void main(String[] args) - this is the usual main method for Java. In this case, we’ll handle input and output in this method
  • String convert(double cups, int units) - this method will help us select the proper conversion to be performed based on user input
  • double toOunces(double cups) - this method will convert the given number of cups to fluid ounces
  • double toTablespoons(double cups) - this method will convert the given number of cups to tablespoons
  • double toTeaspoons(double cups) - this method will convert the given number of cups to teaspoons

Control Flow

Now that we have an idea of what methods we need, let’s discuss the overall control flow of the program and the order in which the methods will be used.

The program will start in the main method, just like any other Java program. That method will prompt the user to input a number of cups to be converted, and also will ask the user to choose which conversion to be performed. Once we have those two inputs, we can then perform the computation in the program.

At that point, the main method will call the convert method and provide the two inputs as arguments to that method call. We’ll use the convert method to determine which of the other methods to call, based on the units parameter. That method will then call the appropriate conversion method (either toOunces, toTablespoons or toTeaspoons) and then use the value returned by that method to build the output string.

Each conversion method is very simple - it just uses a bit of math to convert the value in cups to the appropriate value for a different unit of measurement, and then it will return that value.

Scaffolding the Program

Now that we’ve decided what methods to include, we can go ahead and start building the overall structure for our program. It should contain a single class named Converter and the methods listed above. Finally, since we are reading input interactively from the terminal, we’ll also need to remember to import the java.util.Scanner class. So, our overall structure might look like this:

import java.util.Scanner;

public class Converter{

    public static void main(String[] args){
        // Create scanner to read input
        Scanner scanner = new Scanner(System.in);
        // more code here
    }

    static String convert(double cups, int units) {
        // more code here
        return "";
    }

    static double toOunces(double cups){
        // more code here
        return -1.0;
    }

    static double toTablespoons(double cups){
        // more code here
        return -1.0;
    }

    static double toTeaspoons(double cups){
        // more code here
        return -1.0;
    }
}

Notice that each method signature includes the modifiers public and static along with the return type, name of the method, and a list of parameters expected. For every method that returns a value, we’ve also included a default return statement so that the code will compile at this point. Methods that have void as a return type, such as the main method, don’t need to include a return statement.

Also, the order in which the methods are declared inside of a class does not matter in Java. By convention, the main method is typically either the first or the last method declared in the class.

Conversion Methods

Next, we can start filling in the code for the methods. Typically we’d either want to start with the main method, or start with the methods that will be called last in the control flow. In this example, let’s start with the methods that will be called last, which are the conversion methods toOunces, toTablespoons, and toTeaspoons.

We can start with the toOunces method. A standard cup is 8 fluid ounces. So, our method would include this code:

public static double toOunces(double cups){
    return cups * 8.0;
}

That method turns out to be very simple! We can use the same process to write the other two methods. Some helpful conversions:

  • 1 cup is 8 fluid ounces
  • 1 cup is 16 tablespoons
  • 1 cup is 48 teaspoons

Testing Methods

At this point we’ve written some code, and we may want to test these methods just to make sure they are working before moving on. So, we can write some code in our main method to quickly call these methods and check their return values. Here’s a quick example:

public static void main(String[] args){
    // testing code - DELETE BEFORE SUBMITTING
    System.out.println("1 cup should be 8 ounces : " + toOunces(1.0));
    System.out.println("1 cup should be 16 tablespoons : " + toTablespoons(1.0));
    System.out.println("1 cup should be 48 teaspoons : " + toTeaspoons(1.0));

    // Create scanner to read input
    Scanner scanner = new Scanner(System.in);
    // more code here
}

If we put that code in the main method and run it, we should see output similar to this:

Converter Example Converter Example

That’s great! That means our methods are working and seem to be returning the correct values. We may want to try a few other values besides 1 cup just to be sure that the output exactly matches what it should be.

convert Method

The convert method contains the logic for selecting the appropriate conversion method, calling it, and then returning a formatted string to be printed. This method requires two parameters: the cups value to be sent to the conversion method, and the units selection from the user that can be used to determine which method to call.

Since the units item is a mutually-exclusive choice, it makes sense to use an if-else if-else structure in this method:

static String convert(double cups, int units) {
    if(units == 1){
        return toOunces(cups) + " ounces";
    } else if (units == 2){
        return toTablespoons(cups) + " tablespoons";
    } else if (units == 3){
        return toTeaspoons(cups) + " teaspoons";
    } else {
        // error condition
        return "";
    }
}

Main Method

Finally, we can write our main method. It should prompt the user for the number of cups and the units to be converted to. It will then call the convert method and print the answer. We should delete our testing code from the main method at this point.

public static void main(String[] args){
    // Create scanner to read input
    Scanner scanner = new Scanner(System.in);
    System.out.print("Please enter the number of cups to convert as a floating-point value: ");
    double cups = Double.parseDouble(scanner.nextLine());
    System.out.print("Select conversion: 1 (ounces), 2 (tablespoons) or 3 (teaspoons): ");
    int units = Integer.parseInt(scanner.nextLine());
    String output = convert(cups, units);
    System.out.prinltn(output);
}

With that code in place, we should be able to compile and test our program!


  1. Idea adapted from Gaddis, Tony “Starting out with JAVA”, 5th ed, Pearson: New York 2012 ↩︎

Subsections of A Worked Example