2-1 Void Methods

The Road Ahead

Object-Oriented Programming (OOP) is a way of designing programs modeled on real-world objects. Most programming languages today are object-oriented because code written in such languages tends to be easier to maintain and reuse. A solid understanding of OOP is key to writing large-scale modern software.

We’ve had some exposure to working with objects and classes so far; for example, String and Scanner. You know that an object includes both data and methods to operate on that data. In the following 12 sessions we’re going to delve into designing our own methods, classes, and objects. By the end you’ll have an excellent grasp of the three pillars of OOP: Encapsulation, Inheritance, and Polymorphism.

Void Methods

As programs become more sophisticated we can deal with complexity by breaking the overall problem down into smaller sub-problems, solving each of these, and then recombining these solutions to solve the original problem. In Computer Science this problem solving technique is called divide and conquer. So far all of our code has resided in the main() method and we’ve called methods from the Math class and String objects. It’s time to learn how to create our own methods!

There are two types of methods in Java. The first are methods that perform some task but do not return a value; for example, the printf() method. These are known as void methods. The second are methods that perform some task and return a result (i.e., a value) that we then need to do something with. For example, the Math.sqrt() method returns a double value that we then need to store in a double variable or display on the screen. These are known as value methods.

We’ll focus on void methods today, and value methods next time.

Consider the following program:

Here’s 3 stars:
***
Here’s 3 more stars:
***

Lines 11 to 13 define a new void method called displayStars(). Line 11 is called the method signature. A method signature defines where the method can be accessed from (in this case it’s public), how it can be called (static), what it returns (void), its name (displayStars), and any parameters that it accepts.

We’ll save a discussion of the public and static keywords for later when we talk about defining classes. For now, please include these keywords whenever you define a method in the same class as main(). When naming methods, the same 6 syntax and style rules as variable names apply. Note how well the name displayStars() reflects what the method does.

In main() we are calling (invoking) this method on lines 5 and 7 by stating its name. The empty parenthesis () are required when defining and invoking the displayStars() method because this indicates that the method does not accept any parameters – more on this below.

In terms of the flow of execution, when the program is run the JVM automatically calls the main() method first. Inside main(), line 4 displays the message “Here’s 3 stars:” then line 5 calls our displayStars() method. From line 5, execution jumps to the displayStars() method starting on line 11. The body of the displayStars() method is denoted by curly braces { .. }. Next, line 12 displays three asterisk (*) characters. After this the closing } of the method is reached which terminates the method. Execution then returns to where it left off when the displayStars() method was called; that is, line 6 will execute next. Lines 6 and 7 repeat this flow.

The Benefits of Methods

The example code above is very simple, but you should already start to see some benefits of using methods:

  1. Code Reuse: Once we’ve defined a method we can call it again and again, this is called code reuse. Code reuse is a huge productivity booster for software developers. You’ve actually been benefiting from code reuse already by reusing code from the Scanner and Math
  2. Clarity: Programs that are broken down into short, focused methods tend to be easier to read and understand than one long main()
  3. Troubleshooting: When each method performs a well-defined task isolating and fixing bugs becomes easier because you can focus on the method with the bug.
  4. Teamwork: Software development is usually a team sport! When programs are broken down into methods it makes it much easier to split up work between team members.

Arguments and Parameters

Recall that the methods of the Math class allow us to pass in one or two data values within parentheses ( .. ). This is very useful because it means that the same method can produce different results depending on the arguments provided – enhanced code reuse! Let’s define a more generalized displayStars() method that accepts an integer value indicating the number of asterisks that we’d like displayed.

Here’s 3 stars:
***
Here’s 10 more stars:
**********

When we call our new displayStars() method (line 7), the data value passed into the method is called an argument. Within the method, the data value being received is called a parameter. Arguments and parameters are just two different words for the same thing, depending on perspective. As an analogy, if I give you a “gift” (argument) and you thank me for the “present” (parameter) we’re both talking about the same object just using different nouns.

Lines 17 to 22, define the displayStars() method that accepts one int parameter called howMany. Within the method it uses the howMany parameter variable to display the required number of asterisk characters. Can you see how the parameter makes this version of the displayStars() method more flexible and reusable in more situations?

Method Overloading

The code above demonstrates another very important concept: method overloading. Method overloading occurs when we have two (or more) methods with the same name but that take different parameters. In other words, the quantity, data types, and/or order of parameters are different.

In the example above we have two versions of the displayStars() method: one that accepts no parameters, and the other that requires one int parameter. So in this case, whenever we call the method displayStars() the JVM will invoke the correct version based on whether we are passing in one argument or not – there will be no confusion. Look in the Java API at the Math class for other examples.  You’ll see that there are overloaded methods for abs() , max(), and min().

Pass-by-Copy

When a primitive-type variable or value is passed as an argument to a method in Java, what is actually passed is a copy of the data. This means that if we modify a parameter variable within a method, it has no effect on variables outside the method. In programming this is called pass-by-copy (or pass-by-value). Consider the following code:

In main(): x = 1, y = 2
In scopeDemo(): x = 3, z = 4
In main(): x = 1, y = 2

On lines 4 and 5 in main() we are declaring 2 variables. These are called local variables because they are only accessible directly within the method in which they are declared, in this case main(). The scope of a variable defines where in the code that variable is visible and can be directly accessed. In this case, the scope of x and y defined in main() is from the line they are declared on until the closing } of the main() method. If we were to try an access variable y inside the scopeDemo() method we would get a compiler error.

When we call the scopeDemo() method on line 7, the local variable y is passed in as an argument. What actually happens is that a copy of the value (2) stored in y is sent to the scopeDemo() method. The scopeDemo() method receives a copy of this value and stores it in a parameter variable named z. You can think of a parameter variable as being like a local variable; the scope of a parameter variable is anywhere within the method it’s associated with. In this case, the parameter variable z can be accessed anywhere within the curly braces { .. } defining the body of the scopeDemo() method but not in main(). Any changes made to the parameter variable z will have no effect outside of the scopeDemo() method.

Within the scopeDemo() method I am also declaring a local variable called x. Because x is a local variable, its scope is from the line it’s declared on to the end of the scopeDemo() method. Even though main() has a local variable of the same name they are two independent variables, it doesn’t matter that they have the same name or not. Any change made to x in scopeDemo() has no impact on x in main() and vice versa. Here is a diagram to illustrate:

Once the closing curly brace } of the scopeDemo() method is reached, the parameter variable z and the local variable x are cleared from memory. If the scopeDemo() method is called again, new copies of x and z will be created and initialized for that method call.

Variable Scope

Obviously the curly braces { .. } are very important when it comes to interpreting the scope of variables! To recap, there are three types of variable scope we have seen so far:

  1. The scope of a loop control variable defined in a for loop header is the body of the for loop and the other two expressions of the for loop header.
  2. The scope of a local variable is the line it is declared on until the closing } of its method. It cannot be accessed from any other method.
  3. The scope of a parameter variable is anywhere within its method body. Like a local variable, it cannot be accessed from any other method.

You Try!

  1.  Object-Oriented Programming has a lot of important terminology to master.  Please keep up with your glossary, it’s a very important learning tool!
  2. Make a countDown() method that uses a loop to display a count-down from 10 to 1.  Demonstrate how to call the method from main().
  3. Enhance the method above so that it accepts two parameters: start and end — to control what number the count-down will start from and end at.
  4. September 26th is the European Day of Languages.  Write a method called translate() that accepts a String parameter containing an English word or phrase and displays the French equivalent on the screen.  Your method should be able to translate the following terms: yes/oui, no/non, please/s’il vous plait, thank you/merci, you’re welcome/il n’y a pas de quoi, goodbye/au revoir.  Your translate() method should ignore case — research the String method equalsIgnoreCase() in the Java API.  If translation is not possible, display “unknown English word/phrase”.  Write a main() method to demonstrate your translate() method.