Figure 19-1: A table of accounts.
Chapter 19
Creating New Java Methods
In This Chapter
Writing methods that work with existing values
Building methods that modify existing values
Making methods that return new values
In Chapters 3 and 4, I introduce Java methods. I show you how to create a main
method and how to call the System.out.println
method. Between that chapter and this one, I make very little noise about methods. In Chapter 18, I introduce a bunch of new methods for you to call, but that’s only half of the story.
This chapter completes the circle. In this chapter, you create your own Java methods — not the tired old main
method that you’ve been using all along, but some new, powerful Java methods.
Defining a Method within a Class
In Chapter 18, Figure 18-6 introduces an interesting notion — a notion that’s at the core of object-oriented programming. Each Java string has its own equals
method. That is, each string has, built within it, the functionality to compare itself with other strings. That’s an important point. When you do object-oriented programming, you bundle data and functionality into a lump called a class. Just remember Barry’s immortal words from Chapter 17:
A class describes the way in which you intend to combine and use pieces of data.
And why are these words so important? They’re important because in object-oriented programming, chunks of data take responsibility for themselves. With object-oriented programming, everything you have to know about a string is located in the file String.java
. So if anybody has problems with the strings, they know just where to look for all the code. That’s great!
So this is the deal — objects contain methods. Chapter 18 shows you how to use an object’s methods, and this chapter shows you how to create an object’s methods.
Making a method
Imagine a table containing the information about three accounts. (If you have trouble imagining such a thing, just look at Figure 19-1.) In the figure, each account has a last name, an identification number, and a balance. In addition (and here’s the important part), each account knows how to display itself on the screen. Each row of the table has its own copy of a display
method.
Figure 19-1: A table of accounts.
The last names in Figure 19-1 may seem strange to you. That’s because I generated the table’s data randomly. Each last name is a haphazard combination of three letters — one uppercase letter followed by two lowercase letters.
To find out how I randomly generate three-letter names, see this chapter’s “Generating words randomly” sidebar.
I need some code to implement the ideas in Figure 19-1. Fortunately, I have some code in Listing 19-1.
Listing 19-1: An Account Class
import java.text.NumberFormat;
import static java.lang.System.out;
class Account {
String lastName;
int id;
double balance;
void display() {
NumberFormat currency =
NumberFormat.getCurrencyInstance();
out.print(“The account with last name “);
out.print(lastName);
out.print(“ and ID number “);
out.print(id);
out.print(“ has balance “);
out.println(currency.format(balance));
}
}
The Account
class in Listing 19-1 defines four things — a lastName
, an id
, a balance
, and a display
. So each instance of Account
class has its own lastName
variable, its own id
variable, its own balance
variable, and its own display
method. These things match up with the four columns in Figure 19-1.
Examining the method’s header
Listing 19-1 contains the display
method’s declaration. Like a main
method’s declaration, the display
declaration has a header and a body (see Chapter 4). The header has two words and some parentheses:
The word
void
tells the computer that, when the display
method is called, the display
method doesn’t return anything to the place that called it.
Later in this chapter, a method does return something. For now, the display
method returns nothing.
The word
display
is the method’s name.
Every method must have a name. Otherwise, you don’t have a way to call the method.
The parentheses contain all the things you’re going to pass to the method when you call it.
When you call a method, you can pass information to that method on the fly. This display
example, with its empty parentheses, looks strange. That’s because no information is passed to the display
method when you call it. That’s okay. I give a meatier example later in this chapter.
Examining the method’s body
The display
method’s body contains some print
and println
calls. The interesting thing here is that the body makes reference to the variables lastName
, id
, and balance
. A method’s body can do that. But with each object having its own lastName
, id
, and balance
variables, what does a variable in the display
method’s body mean?
Well, when I use the Account
class, I create little account objects. Maybe I create an object for each row of the table in Figure 19-1. Each object has its own values for the lastName
, id
, and balance
variables, and each object has its own copy of the display
method.
So take the first display
method in Figure 19-1 — the method for Aju’s account. The display
method for that object behaves as if it had the code in Listing 19-2.
Listing 19-2: How the display Method Behaves When No One’s Looking
/*
* This is not real code:
*/
void display() {
NumberFormat currency =
NumberFormat.getCurrencyInstance();
out.print(“The account with last name “);
out.print(
“Aju”
);
out.print(“ and ID number “);
out.print(
9936
);
out.print(“ has balance “);
out.println(currency.format(
8734.00
));
}
In fact, each of the three display methods behaves as if its body has a slightly different code. Figure 19-2 illustrates this idea for two instances of the Account
class.
Calling the method
To put the previous section’s ideas into action, you need more code. So the next listing (see Listing 19-3) creates instances of the Account
class.
Figure 19-2: Two objects, each with its own display method.
Listing 19-3: Making Use of the Code in Listing 19-1
import java.util.Random;
class ProcessAccounts {
public static void main(String args[]) {
Random myRandom = new Random();
Account anAccount;
for (int i = 0; i < 3; i++) {
anAccount = new Account();
anAccount.lastName = “” +
(char) (myRandom.nextInt(26) + ‘A’) +
(char) (myRandom.nextInt(26) + ‘a’) +
(char) (myRandom.nextInt(26) + ‘a’);
anAccount.id = myRandom.nextInt(10000);
anAccount.balance = myRandom.nextInt(10000);
anAccount.display();
}
}
}
Here’s a summary of the action in Listing 19-3:
Do the following three times:
Create a new object (an instance of
the
Account class).
Randomly generate values for the object’s
lastName,
id and
balance.
Call the object’s
display method.
The first of the three display
calls prints the first object’s lastName
, id
, and balance
values. The second display
call prints the second object’s lastName
, id
, and balance
values. And so on.
A run of the code from Listing 19-3 is shown in Figure 19-3.
Figure 19-3: Running the code in Listing 19-3.
The flow of control
Suppose that you’re running the code in Listing 19-3. The computer reaches the display
method call:
anAccount.display();
At that point, the computer starts running the code inside the display
method. In other words, the computer jumps to the middle of the Account
class’s code (the code in Listing 19-1).
After executing the display
method’s code (that forest of print
and println
calls), the computer returns to the point where it departed from Listing 19-3. That is, the computer goes back to the display
method call and continues on from there.
So when you run the code in Listing 19-3, the flow of action in each loop iteration isn’t exactly from the top to the bottom. Instead, the action goes from the for
loop to the display
method and then back to the for
loop. The whole business is pictured in Figure 19-4.
Figure 19-4: The flow of control between Listings 19-1 and 19-3.
Using punctuation
In Listing 19-3, notice the use of dots. To refer to the lastName
stored in the anAccount
object, you write
anAccount.lastName
To get the anAccount
object to display
itself, you write
anAccount.display();
That’s great! When you refer to an object’s variable or call an object’s method, the only difference is parentheses:
To refer to an object’s variable, you don’t use parentheses.
To call an object’s method, you use parentheses.
The versatile plus sign
The program in Listing 19-3 uses some cute tricks. In Java, you can do two different things with a plus sign:
You can add numbers with a plus sign.
For example, you can write
numberOfSheep = 2 + 5;
You can concatenate strings with a plus sign.
When you concatenate strings, you scrunch them together, one right after another. For example, the expression
“Barry” + “ “ + “Burd”
scrunches together Barry
, a blank space, and Burd
. The new scrunched-up string is (you guessed it) Barry Burd
.
In Listing 19-3, the statement
anAccount.lastName = “”
+
(char) (myRandom.nextInt(26) + ‘A’)
+
(char) (myRandom.nextInt(26) + ‘a’)
+
(char) (myRandom.nextInt(26) + ‘a’);
has many plus signs, and some of the plus signs concatenate things together. The first thing is a mysterious empty string (“”
). This empty string is invisible, so it never gets in the way of your seeing the second, third, and fourth things.
Onto the empty string, the program concatenates a second thing. This second thing is the value of the expression (char) (myRandom.next Int(26) + ‘A’)
. The expression may look complicated, but it’s really no big deal. This expression represents an uppercase letter (any uppercase letter, generated randomly).
Onto the empty string and the uppercase letter, the program concatenates a third thing. This third thing is the value of the expression (char) (my Random.nextInt(26) + ‘a’)
. This expression represents a lowercase letter (any lowercase letter, generated randomly).
Onto all this stuff, the program concatenates another lowercase letter. So altogether, you have a randomly generated three-letter name. For more details, see the sidebar.
Let the Objects Do the Work
When I was a young object, I wasn’t as smart as the objects you have nowadays. Consider, for example, the object in Listing 19-4. Not only does this object display itself, but the object can also fill itself with values.
Listing 19-4: A Class with Two Methods
import java.util.Random;
import java.text.NumberFormat;
import static java.lang.System.out;
class BetterAccount {
String lastName;
int id;
double balance;
void fillWithData() {
Random myRandom = new Random();
lastName = “” +
(char) (myRandom.nextInt(26) + ‘A’) +
(char) (myRandom.nextInt(26) + ‘a’) +
(char) (myRandom.nextInt(26) + ‘a’);
id = myRandom.nextInt(10000);
balance = myRandom.nextInt(10000);
}
void display() {
NumberFormat currency =
NumberFormat.getCurrencyInstance();
out.print(“The account with last name “);
out.print(lastName);
out.print(“ and ID number “);
out.print(id);
out.print(“ has balance “);
out.println(currency.format(balance));
}
}
I wrote some code to use the class in Listing 19-4. This new code is in Listing 19-5.
Listing 19-5: This Is So Cool!
class ProcessBetterAccounts {
public static void main(String args[]) {
BetterAccount
anAccount;
for (int i = 0; i < 3; i++) {
anAccount = new
BetterAccount
();
anAccount.fillWithData();
anAccount.display();
}
}
}
Listing 19-5 is pretty slick. Because the code in Listing 19-4 is so darn smart, the new code in Listing 19-5 has very little work to do. This new code just creates a BetterAccount
object and then calls the methods in Listing 19-4. When you run all this stuff, you get results like the ones in Figure 19-3.
Passing Values to Methods
Think about sending someone to the supermarket to buy bread. When you do this, you say, “Go to the supermarket and buy some bread.” (Try it at home. You’ll have a fresh loaf of bread in no time at all!) Of course, some other time, you send that same person to the supermarket to buy bananas. You say, “Go to the supermarket and buy some bananas.” And what’s the point of all this? Well, you have a method, and you have some on-the-fly information that you pass to the method when you call it. The method is named “Go to the supermarket and buy some. . . .” The on-the-fly information is either “bread” or “bananas,” depending on your culinary needs. In Java, the method calls would look like this:
goToTheSupermarketAndBuySome(bread);
goToTheSupermarketAndBuySome(bananas);
The things in parentheses are called parameters or parameter lists. With parameters, your methods become much more versatile. Instead of getting the same thing each time, you can send somebody to the supermarket to buy bread one time, bananas another time, and birdseed the third time. When you call your goToTheSupermarketAndBuySome
method, you decide right there and then what you’re going to ask your pal to buy.
These concepts are made more concrete in Listings 19-6 and 19-7.
Listing 19-6: Adding Interest
import java.text.NumberFormat;
import static java.lang.System.out;
class NiceAccount {
String lastName;
int id;
double balance;
void addInterest(double rate) {
out.print(“Adding “);
out.print(rate);
out.println(“ percent...”);
balance += balance * (rate / 100.0);
}
void display() {
NumberFormat currency =
NumberFormat.getCurrencyInstance();
out.print(“The account with last name “);
out.print(lastName);
out.print(“ and ID number “);
out.print(id);
out.print(“ has balance “);
out.println(currency.format(balance));
}
}
Listing 19-7: Calling the addInterest Method
import java.util.Random;
class ProcessNiceAccounts {
public static void main(String args[]) {
Random myRandom = new Random();
NiceAccount
anAccount;
double interestRate;
for (int i = 0; i < 3; i++) {
anAccount = new
NiceAccount
();
anAccount.lastName = “” +
(char) (myRandom.nextInt(26) + ‘A’) +
(char) (myRandom.nextInt(26) + ‘a’) +
(char) (myRandom.nextInt(26) + ‘a’);
anAccount.id = myRandom.nextInt(10000);
anAccount.balance = myRandom.nextInt(10000);
anAccount.display();
interestRate = myRandom.nextInt(5);
anAccount.addInterest(interestRate);
anAccount.display();
System.out.println();
}
}
}
In Listing 19-7, the line
anAccount.addInterest(interestRate);
plays the same role as the line goToTheSupermarketAndBuySome(bread)
in my little supermarket example. The word addInterest
is a method name, and the word interestRate
in parentheses is a parameter. Taken as a whole, this statement tells the code in Listing 19-6 to execute its addInterest
method. This statement also tells Listing 19-6 to use a certain number (whatever value is stored in the interestRate
variable) in the method’s calculations. The value of interestRate
can be 1.0, 2.0, or whatever other value you get by calling myRandom.nextInt(5)
. In the same way, the goToTheSupermarketAndBuySome
method works for bread, bananas, or whatever else you need from the market.
The next section has a detailed description of addInterest
and its action. In the meantime, a run of the code in Listings 19-6 and 19-7 is shown in Figure 19-5.
Figure 19-5: Running the code in Listing 19-7.
Handing off a value
When you call a method, you can pass information to that method on the fly. This information is in the method’s parameter list. Listing 19-7 has a call to the addInterest
method:
anAccount.addInterest(interestRate);
The first time through the loop, the value of interestRate
is 2.0. (Remember, I’m using the data in Figure 19-5.) So at that point in the program’s run, the method call behaves as if it’s the following statement:
anAccount.addInterest(2.0);
The computer is about to run the code inside the addInterest
method (a method in Listing 19-6). But first, the computer passes the value 2.0 to the parameter in the addInterest
method’s header. So inside the addInterest
method, the value of rate
becomes 2.0. For an illustration of this idea, see Figure 19-6.
Here’s something interesting. The parameter in the addInterest
method’s header is rate
. But, inside the ProcessNiceAccounts
class, the parameter in the method call is interestRate
. That’s okay. In fact, it’s standard practice.
Figure 19-6: Passing a value to a method’s parameter.
In Listings 19-6 and 19-7, the names of the parameters don’t have to be the same. The only thing that matters is that both parameters (rate
and interestRate
) have the same type. In Listings 19-6 and 19-7, both of these parameters are of type double
. So everything is fine.
Inside the addInterest
method, the +=
assignment operator adds balance * (rate / 100.0)
to the existing balance
value. For some info about the +=
assignment operator, see Chapter 7.
Working with a method header
In the next few bullets, I make some observations about the addInterest
method header (in Listing 19-6):
The word
void
tells the computer that when the addInterest
method is called, the addInterest
method doesn’t send a value back to the place that called it.
The next section has an example in which a method sends a value back.
The word
addInterest
is the method’s name.
That’s the name you use to call the method when you’re writing the code for the ProcessNiceAccounts
class (see Listing 19-7).
The parentheses in the header contain placeholders for all the things you’re going to pass to the method when you call it.
When you call a method, you can pass information to that method on the fly. This information is the method’s parameter list. The addInterest
method’s header says that the addInterest
method takes one piece of information, and that piece of information must be of type double
:
void addInterest(double
rate)
Sure enough, if you look at the call to addInterest
(down in the ProcessNiceAccounts
class’s main
method), that call has the variable interestRate
in it. And interestRate
is of type double
. When I call getInterest
, I’m giving the method a value of type double
.
How the method uses the object’s values
The addInterest
method in Listing 19-6 is called three times from the main
method in Listing 19-7. The actual account balances and interest rates are different each time:
In the first call of Figure 19-5, the
balance
is 8983.00, and the interest rate is 2.0.
When this call is made, the expression balance * (rate / 100.0)
stands for 8983.00 * (2.0 / 100.00). See Figure 19-7.
In the second call of Figure 19-5, the balance is 3756.00, and the interest rate is 0.0.
When the call is made, the expression balance * (rate / 100.0)
stands for 3756.00 * (0.0 / 100.00). Again, see Figure 19-7.
In the third call of Figure 19-5, the balance is 8474.00, and the interest rate is 3.0.
When the addInterest
call is made, the expression balance * (rate / 100.0)
stands for 8474.00 * (3.0 / 100.00).
Figure 19-7: Cbj’s account and Bry’s account.
Getting a Value from a Method
Say that you’re sending a friend to buy groceries. You make requests for groceries in the form of method calls. You issue calls such as
goToTheSupermarketAndBuySome(bread);
goToTheSupermarketAndBuySome(bananas);
The things in parentheses are parameters. Each time you call your goToTheSupermarketAndBuySome
method, you put a different value in the method’s parameter list.
Now what happens when your friend returns from the supermarket? “Here’s the bread you asked me to buy,” says your friend. As a result of carrying out your wishes, your friend returns something to you. You made a method call, and the method returns information (or better yet, the method returns some food).
The thing returned to you is called the method’s return value, and the type of thing returned to you is called the method’s return type.
An example
To see how return values and a return types work in a real Java program, check out the code in Listings 19-8 and 19-9.
Listing 19-8: A Method That Returns a Value
import java.text.NumberFormat;
import static java.lang.System.out;
class GoodAccount {
String lastName;
int id;
double balance;
double getInterest(double rate) {
double interest;
out.print(“Adding “);
out.print(rate);
out.println(“ percent...”);
interest = balance * (rate / 100.0);
return interest;
}
void display() {
NumberFormat currency =
NumberFormat.getCurrencyInstance();
out.print(“The account with last name “);
out.print(lastName);
out.print(“ and ID number “);
out.print(id);
out.print(“ has balance “);
out.println(currency.format(balance));
}
}
Listing 19-9: Calling the Method in Listing 19-8
import java.util.Random;
import java.text.NumberFormat;
class ProcessGoodAccounts {
public static void main(String args[]) {
Random myRandom = new Random();
NumberFormat currency =
NumberFormat.getCurrencyInstance();
GoodAccount
anAccount;
double interestRate;
double yearlyInterest;
for (int i = 0; i < 3; i++) {
anAccount = new GoodAccount();
anAccount.lastName = “” +
(char) (myRandom.nextInt(26) + ‘A’) +
(char) (myRandom.nextInt(26) + ‘a’) +
(char) (myRandom.nextInt(26) + ‘a’);
anAccount.id = myRandom.nextInt(10000);
anAccount.balance = myRandom.nextInt(10000);
anAccount.display();
interestRate = myRandom.nextInt(5);
yearlyInterest =
anAccount.getInterest(interestRate);
System.out.print(“This year’s interest is “);
System.out.println
(currency.format(yearlyInterest));
System.out.println();
}
}
}
To see a run of code from Listings 19-8 and 19-9, take a look at Figure 19-8.
Figure 19-8: Running the code in Listing 19-9.
How return types and return values work
I want to trace a piece of the action in Listings 19-8 and 19-9. For input data, I use the first set of values in Figure 19-8.
Here’s what happens when getInterest
is called (you can follow along in Figure 19-9):
The value of
balance
is 9508.00, and the value of rate
is 2.0. So the value of balance * (rate / 100.0)
is 190.16 — one-hundred ninety dollars and sixteen cents.
The value 190.16 gets assigned to the
interest
variable, so the statement
return interest;
has the same effect as
return 190.16;
The
return
statement sends this value 190.16 back to the code that called the method. At that point in the process, the entire method call in Listing 19-9 — anAccount.getInterest(interestRate)
— takes on the value 190.16.
Finally, the value 190.16 gets assigned to the variable
yearlyInterest
.
Figure 19-9: A method call is an expression with a value.
Working with the method header (again)
When you create a method or a method call, you have to be careful to use Java’s types consistently. So make sure that you check for the following:
In Listing 19-8, the
getInterest
method’s header starts with the word double
. So when the method is executed, it should send a double
value back to the place that called it.
Again in Listing 19-8, the last statement in the
getInterest
method is return interest
. So the method returns whatever value is stored in the interest
variable, and the interest
variable has type double
. So far, so good.
In Listing 19-9, the value returned by the call to
getInterest
is assigned to a variable named yearlyInterest
. Sure enough, yearlyInterest
is of type double
.
That settles it! The use of types in the handling of method getInterest
is consistent in Listings 19-8 and 19-9. I’m thrilled!