Figure 18-1: Running the code in Listing 18-1.
Chapter 18
Using Methods and Variables from a Java Class
In This Chapter
Using Java’s String class
Calling methods
Understanding static and non-static methods and variables
Making numbers look good
I hope you didn’t read Chapter 17 because I tell a big lie in the beginning of the chapter. Actually, it’s not a lie. It’s an exaggeration.
Actually, it’s not an exaggeration. It’s a careful choice of wording. In Chapter 17, I write that the gathering of data into a class is the start of object-oriented programming. Well, that’s true. Except that many programming languages had data-gathering features before object-oriented programming became popular. Pascal had records. C had structs.
To be painfully precise, the grouping of data into usable chunks is only a prerequisite to object-oriented programming. You’re not really doing object-oriented programming until you combine both data and methods in your classes.
This chapter starts the “data and methods” ball rolling, and Chapter 19 rounds out the picture.
The String Class
The String
class is declared in the Java API. This means that, somewhere in the stuff you download from java.com
is a file named String.java
. If you hunt down this String.java
file and peek at the file’s code, you find some very familiar-looking stuff:
class String {
...And so on.
In your own code, you can use this String
class without ever seeing what’s inside the String.java
file. That’s one of the great things about object-oriented programming.
A simple example
A String
is bunch of characters. It’s like having several char
values in a row. You can declare a variable to be of type String
and store several letters in the variable. Listing 18-1 has a tiny example.
Listing 18-1: I’m Repeating Myself Again (Again)
import java.util.Scanner;
class JazzyEchoLine {
public static void main(String args[]) {
Scanner myScanner = new Scanner(System.in);
String lineIn;
lineIn
= myScanner.nextLine();
System.out.println(
lineIn
);
}
}
A run of Listing 18-1 is shown in Figure 18-1. This run bears an uncanny resemblance to runs of Listing 5-1 from Chapter 5. That’s because Listing 18-1 is a reprise of the effort in Listing 5-1.
Figure 18-1: Running the code in Listing 18-1.
The new idea in Listing 18-1 is the use of a String
. In Listing 5-1, I have no variable to store the user’s input. But in Listing 18-1, I create the lineIn
variable. This variable stores a bunch of letters, like the letters Do as I write, not as I do
.
Putting String variables to good use
The program in Listing 18-1 takes the user’s input and echoes it back on the screen. This is a wonderful program, but (like many college administrators that I know) it doesn’t seem to be particularly useful.
So take a look at a more useful application of Java’s String
type. A nice one is in Listing 18-2.
Listing 18-2: Putting a Name in a String Variable
import java.util.Scanner;
import static java.lang.System.out;
class ProcessMoreData {
public static void main(String args[]) {
Scanner myScanner = new Scanner(System.in);
String fullName;
double amount;
boolean taxable;
double total;
out.print(“Customer’s full name: “);
fullName = myScanner.nextLine();
out.print(“Amount: “);
amount = myScanner.nextDouble();
out.print(“Taxable? (true/false) “);
taxable = myScanner.nextBoolean();
if (taxable) {
total = amount * 1.05;
} else {
total = amount;
}
out.println();
out.print(“The total for “);
out.print(fullName);
out.print(“ is “);
out.print(total);
out.println(“.”);
}
}
A run of the code in Listing 18-2 is shown in Figure 18-2. The code stores Barry A. Burd
in a variable called fullName
and displays the fullName
variable’s content as part of the output. To make this program work, you have to store Barry A. Burd
somewhere. After all, the program follows a certain outline:
Get
a name
.
Get some other stuff.
Compute the total.
Display the name
(along with some other stuff).
If you don’t have the program store the name somewhere then, by the time it’s done getting other stuff and computing the total, it forgets the name (so the program can’t display the name).
Figure 18-2: Making a purchase.
Reading and writing strings
To read a String
value from the keyboard, you can call either next
or next Line
:
The method
next
reads up to the next blank space.
For example, with the input Barry A. Burd
, the statements
String firstName = myScanner.next();
String middleInit = myScanner.next();
String lastName = myScanner.next();
assign Barry
to firstName
, A.
to middleInit
, and Burd
to lastName
.
The method
nextLine
reads up to the end of the current line.
For example, with input Barry A. Burd
, the statement
String fullName = myScanner.nextLine();
assigns Barry A. Burd
to the variable fullName
. (Hey, being an author has some hidden perks.)
To display a String
value, you can call one of your old friends, System.out.print
or System.out.println
. In fact, most of the programs in this book display String
values. In Listing 18-2, a statement like
out.print(“Customer’s full name: “);
displays the String
value “Customer’s full name: “
.
Chapter 4 introduces a bunch of characters, enclosed in double quote marks:
“Chocolate, royalties, sleep”
In Chapter 4, I call this a literal of some kind. (It’s a literal because, unlike a variable, it looks just like the stuff that it represents.) Well, in this chapter, I can continue the story about Java’s literals:
In Listing 18-2,
amount
and total
are double
variables, and 1.05
is a double
literal.
In Listing 18-2,
fullName
is a String
variable, and things like “Customer’s full name: “
are String
literals.
Using an Object’s Methods
If you’re not too concerned about classes and reference types, then the use of the type String
in Listing 18-2 is no big deal. Almost everything you can do with a primitive type seems to work with the String
type as well. But there’s danger around the next curve. Take a look at the code in Listing 18-3 and the run of the code shown in Figure 18-3.
Listing 18-3: A Faulty Password Checker
/*
* This code does not work:
*/
import java.util.Scanner;
import static java.lang.System.out;
class TryToCheckPassword {
public static void main(String args[]) {
Scanner myScanner = new Scanner(System.in);
String password = “swordfish”;
String userInput;
out.print(“What’s the password? “);
userInput = myScanner.next();
if (
password == userInput
) {
out.println(
“You’re okay!”
);
} else {
out.println(
“You’re a menace.”
);
}
}
}
Figure 18-3: But I typed the correct password!
Here are the facts as they appear in this example:
According to the code in Listing 18-3, the value of
password
is “sword fish”
.
In Figure 18-3, in response to the program’s prompt, the user types
swordfish
. So in the code, the value of userInput
is “swordfish”
.
The
if
statement checks the condition password == userInput
. Because both variables have the value “swordfish”
, the condition should be true, but. . . .
The condition is not true because the program’s output is
You’re a menace.
What’s going on here? I try beefing up the code to see if I can find any clues. An enhanced version of the password-checking program is in Listing 18-4, with a run of the new version shown in Figure 18-4.
Listing 18-4: An Attempt to Debug the Code in Listing 18-3
import java.util.Scanner;
import static java.lang.System.out;
class DebugCheckPassword {
public static void main(String args[]) {
Scanner myScanner = new Scanner(System.in);
String password = “swordfish”;
String userInput;
out.print(“What’s the password? “);
userInput = myScanner.next();
out.println();
out.print(“You typed “);
out.println(userInput);
out.print(“But the password is “);
out.println(password);
out.println();
if (password == userInput) {
out.println(“You’re okay!”);
} else {
out.println(“You’re a menace.”);
}
}
}
Figure 18-4: This looks even worse.
Ouch! I’m stumped this time. The run in Figure 18-4 shows that both the userInput
and password
variables have value swordfish
. So why doesn’t the program accept the user’s input?
When you compare two things with a double equal sign, reference types and primitive types don’t behave the same way. Consider, for example, int
versus String
:
You can compare two
int
values with a double equal sign. When you do, things work exactly as you would expect. For example, the condition in the following code is true:
int apples = 7;
int oranges = 7;
if (apples == oranges) {
System.out.println(“They’re equal.”);
}
When you compare two
String
values with the double equal sign, things don’t work the way you expect. The computer doesn’t check to see if the two String
values contain the same letters. Instead, the computer checks some esoteric property of the way variables are stored in memory.
Comparing strings
In the preceding bullets, the difference between int
and String
is mighty interesting. But if the double equal sign doesn’t work for String
values, how do you check to see if Joe User enters the correct password? You do it with the code in Listing 18-5.
Listing 18-5: Calling an Object’s Method
/*
* This program works!
*/
import java.util.Scanner;
import static java.lang.System.out;
class CheckPassword {
public static void main(String args[]) {
Scanner myScanner = new Scanner(System.in);
String password = “swordfish”;
String userInput;
out.print(“What’s the password? “);
userInput = myScanner.next();
if (
password.equals(userInput)
) {
out.println(“You’re okay!”);
} else {
out.println(“You’re a menace.”);
}
}
}
A run of the new password-checking code is shown in Figure 18-5 and, let me tell you, it’s a big relief! The code in Listing 18-5 actually works! When the user types swordfish
, the if
statement’s condition is true.
Figure 18-5: At last, Joe User can log in.
The truth about classes and methods
The magic in Listing 18-5 is the use of a method named equals
. I have two ways to explain the equals
method — a simple way, and a more detailed way. First, here’s the simple way: The equals
method compares the characters in one string with the characters in another. If the characters are the same, then the condition inside the if
statement is true. That’s all there is to it.
For a more detailed understanding of the equals
method, flip to Chapter 17 and take a look at Figures 17-7 and 17-8. Those figures illustrate the similarities between classes, objects, and the parts of a table. In the figures, each row represents a purchase, and each column represents a feature that purchases possess.
You can observe the same similarities for any class, including Java’s String
class. In fact, what Figure 17-7 does for purchases, Figure 18-6 does for strings.
Figure 18-6: Viewing the String class and String objects as parts of a table.
The stuff shown in Figure 18-6 is much simpler than the real String
class story. But Figure 18-6 makes a good point. Like the purchases in Figure 17-7, each string has its own features. For example, each string has a value
(the actual characters stored in the string), and each string has a count
(the number of characters stored in the string). You can’t really write the following line of code:
//This code does
NOT
work:
System.out.println(password.count);
but that’s because the stuff in Figure 18-6 omits a few subtle details.
Anyway, each row in Figure 18-6 has three items — a value
, a count
, and an equals
method. So each row of the table contains more than just data. Each row contains an equals
method, a way of doing something useful with the data. It’s as if each object (each instance of the String
class) has three things:
A bunch of characters (the object’s
value
)
A number (the object’s
count
)
A way of being compared with other strings (the object’s
equals
method)
That’s the essence of object-oriented programming. Each string has its own personal copy of the equals
method. For example, in Listing 18-5, the password
string has its own equals
method. When you call the password
string’s equals
method and put the userInput
string in the method’s parentheses, the method compares the two strings to see if those strings contain the same characters.
The userInput
string in Listing 18-5 has an equals
method, too. I could use the userInput
string’s equals
method to compare this string with the password
string. But I don’t. In fact, in Listing 18-5, I don’t use the userInput
string’s equals
method at all. (To compare the userInput
with the password
, I had to use either the password
string’s equals
method or the userInput
string’s equals
method. So I made an arbitrary choice: I chose the password
string’s method.)
Calling an object’s methods
Calling a string’s equals
method is like getting a purchase’s total
. With both equals
and total
, you use your old friend, the dot. For example, in Listing 17-3, you write
System.out.println(
onePurchase.total
);
and in Listing 18-5, you write
if (
password.equals
(userInput))
A dot works the same way for an object’s variables and its methods. In either case, a dot takes the object and picks out one of the object’s parts. It works whether that part is a piece of data (as in onePurchase.total
) or a method (as in password.equals
).
Combining and using data
At this point in the chapter, I can finally say, “I told you so.” Here’s a quotation from Chapter 17:
A class is a design plan. The class describes the way in which you intend to combine and use pieces of data.
A class can define the way you use data. How do you use a password and a user’s input? You check to see if they’re the same. That’s why Java’s String
class defines an equals
method.
Static Methods
You have a fistful of checks. Each check has a number, an amount, and a payee. You print checks like these with your very own laser printer. To print the checks, you use a Java class. Each object made from the Check
class has three variables (number
, amount
, and payee
). And each object has one method (a print
method). You can see all this in Figure 18-7.
You’d like to print the checks in numerical order. So you need a method to sort the checks. If the checks in Figure 18-7 were sorted, the check with number 1699 would come first, and the check with number 1705 would come last.
Figure 18-7: The Check class and some check objects.
The big question is, should each check have its own sort
method? Does the check with number 1699 need to sort itself? And the answer is no. Some methods just shouldn’t belong to the objects in a class.
So where do such methods belong? How can you have a sort
method without creating a separate sort
for each check?
Here’s the answer. You make the sort
method be static. Anything that’s static belongs to a whole class, not to any particular instance of the class. If the sort
method is static, then the entire Check
class has just one copy of the sort
method. This copy stays with the entire Check
class. No matter how many instances of the Check
class you create — three, ten, or none — you have just one sort
method.
For an illustration of this concept, refer to Figure 18-7. The whole class has just one sort
method. So the sort
method is static. No matter how you call the sort
method, that method uses the same values to do its work.
Of course, each individual check (each object, each row of the table in Figure 18-7) still has its own number
, its own amount
, its own payee
, and its own print
method. When you print
the first check, you get one amount, and when you print
the second check get another. Because there’s a number
, an amount
, a payee
, and a print
method for each object, I call these things non-static. I call them non-static because . . . well . . . because they’re not static.
Calling static and non-static methods
In this book, my first use of the word static
is in Listing 3-1. I use static
as part of every main
method (and this book’s listings have lots of main
methods). In Java, your main
method has to be static. That’s just the way it goes.
To call a static method, you use a class’s name along with a dot. This is just slightly different from the way you call a non-static method:
To call an ordinary (non-static) method, you follow an object with a dot.
For example, a program to process the checks in Figure 18-7 may contain code of the following kind:
Check firstCheck;
firstCheck.number = 1705;
firstCheck.amount = 25.09;
firstCheck.payee = “The Butcher”;
firstCheck
.print();
To call a class’s static method, you follow the class name with a dot.
For example, to sort the checks in Figure 18-7, you may call
Check
.sort();
Turning strings into numbers
The code in Listing 18-5 introduces a non-static method named equals
. To compare the password
string with the userInput
string, you preface .equals
with either of the two string objects. In Listing 18-5, I preface .equals
with the password
object:
if (password.equals(userInput))
Each string object has an equals
method of its own, so I can achieve the same effect by writing
if (userInput.equals(password))
But Java has another class named Integer
, and the whole Integer
class has a static method named parseInt
. If someone hands you a string of characters, and you want to turn that string into an int
value, you can call the Integer
class’s parseInt
method. Listing 18-6 has a small example.
Listing 18-6: More Chips, Please
import java.util.Scanner;
import static java.lang.System.out;
class AddChips {
public static void main(String args[]) {
Scanner myScanner = new Scanner(System.in);
String reply;
int numberOfChips;
out.print(“How many chips do you have?”);
out.print(“ (Type a number,”);
out.print(“ or type ‘Not playing’) “);
reply = myScanner.nextLine();
if (
!reply.equals(“Not playing”)
) {
numberOfChips =
Integer.parseInt(reply)
;
numberOfChips += 10;
out.print(“You now have “);
out.print(numberOfChips);
out.println(“ chips.”);
}
}
}
Some runs of the code in Listing 18-6 are shown in Figure 18-8. You want to give each player ten chips. But some party poopers in the room aren’t playing. So two people, each with no chips, may not get the same treatment. An empty-handed player gets ten chips, but an empty-handed party pooper gets none.
So in Listing 18-6, you call the Scanner
class’s nextLine
method, allowing a user to enter any characters at all — not just digits. If the user types Not playing
, then you don’t give the killjoy any chips.
Figure 18-8: Running the code in Listing 18-6.
If the user types some digits, then you’re stuck holding these digits in the string variable named reply
. You can’t add ten to a string like reply
. So you call the Integer
class’s parseInt
method, which takes your string and hands you back a nice int
value. From there, you can add ten to the int
value.
Turning numbers into strings
In Chapter 17, Listing 17-1 adds tax to the amount of a purchase. But a run of the code in Listing 17-1 has an anomaly. Refer to Figure 17-1. With 5 percent tax on 20 dollars, the program displays a total of 21.0
. That’s peculiar. Where I come from, currency amounts aren’t normally displayed with just one digit beyond the decimal point.
If you don’t choose your purchase amount carefully, the situation is even worse. For example, in Figure 18-9, I run the same program (the code in Listing 17-1) with purchase amount 19.37. The resulting display looks very nasty.
With its internal zeros and ones, the computer doesn’t do arithmetic quite the way you and I are used to doing it. So how do you fix this problem?
Figure 18-9: Do you have change for 20.3385000 00000003?
The Java API has a class named NumberFormat
, and the NumberFormat
class has a static method named getCurrencyInstance
. When you call NumberFormat.getCurrencyInstance()
with nothing inside the parentheses, you get an object that can mold numbers into U.S. currency amounts. Listing 18-7 has an example.
Listing 18-7: The Right Way to Display a Dollar Amount
import java.text.NumberFormat;
import java.util.Scanner;
class BetterProcessData {
public static void main(String args[]) {
Scanner myScanner = new Scanner(System.in);
double amount;
boolean taxable;
double total;
NumberFormat currency =
NumberFormat.getCurrencyInstance();
String niceTotal;
System.out.print(“Amount: “);
amount = myScanner.nextDouble();
System.out.print(“Taxable? (true/false) “);
taxable = myScanner.nextBoolean();
if (taxable) {
total = amount * 1.05;
} else {
total = amount;
}
niceTotal = currency.format(total);
System.out.print(“Total: “);
System.out.println(niceTotal);
}
}
For some beautiful runs of the code in Listing 18-7, see Figure 18-10. Now at last, you see a total like $20.34
, not 20.338500000000003
. Ah! That’s much better.
How the NumberFormat works
For my current purposes, the code in Listing 18-7 contains three interesting variables:
The variable
total
stores a number, such as 21.0.
The variable
currency
stores an object that can mold numbers into U.S. currency amounts.
The variable
niceTotal
is set up to store a bunch of characters.
Figure 18-10: See the pretty numbers.
The currency
object has a format
method. So to get the appropriate bunch of characters into the niceTotal
variable, you call the currency
object’s format
method. You apply this format method to the variable total
.
Understanding the Big Picture
In this section, I answer some of the burning questions that I raise throughout the book. “What does java.util
stand for?” “Why do I need the word static
at certain points in the code?” “How can a degree in Horticultural Studies help you sort cancelled checks?”
I also explain “static” in some unique and interesting ways. After all, static methods and variables aren’t easy to understand. It helps to read about Java’s static feature from several points of view.
Packages and import declarations
In Java, you can group a bunch of classes into something called a package. In fact, the classes in Java’s standard API are divided into about 200 packages. This book’s examples make heavy use of three packages — the packages named java.util
, java.lang
, and java.io
.
The class java.util.Scanner
The package java.util
contains about 50 classes, including the very useful Scanner
class. Like most other classes, this Scanner
class has two names — a fully qualified name and an abbreviated simple name. The class’s fully qualified name is java.util.Scanner
, and the class’s simple name is Scanner
. You get the fully qualified name by adding the package name to the class’s simple name. (That is, you add the package name java.util
to the simple name Scanner
. You get java.util.Scanner
.)
An import declaration lets you abbreviate a class’s name. With the declaration
import java.util.Scanner;
the Java compiler figures out where to look for the Scanner
class. So instead of writing java.util.Scanner
throughout your code, you can just write Scanner
.
The class java.lang.System
The package java.lang
contains about 35 classes, including the ever-popular System
class. (The class’s fully qualified name is java.lang.System
, and the class’s simple name is System
.) Instead of writing java.lang.System
throughout your code, you can just write System
. You don’t even need an import
declaration.
The static System.out variable
What kind of importing must you do in order to abbreviate System.out.println
? How can you shorten it to out.println
? An import declaration lets you abbreviate a class’s name. But in the expression System.out
, the word out
isn’t a class. The word out
is a static variable. (The out
variable refers to the place where a Java program sends text output.) So you can’t write
//This code is
bogus
. Don’t use it:
import java.lang.System.out;
What do you do instead? You write
import
static
java.lang.System.out;
To find out more about the out
variable’s being a static variable, read the next section.
Shedding light on the static darkness
I love to quote myself. When I quote my own words, I don’t need written permission. I don’t have to think about copyright infringement, and I never hear from lawyers. Best of all, I can change and distort anything I say. When I paraphrase my own ideas, I can’t be misquoted.
With that in mind, here’s a quote from the previous section:
“Anything that’s static belongs to a whole class, not to any particular instance of the class. . . . To call a static method, you use a class’s name along with a dot.”
How profound! In Listing 18-6, I introduce a static method named parseInt
. Here’s the same quotation applied to the static parseInt
method:
The static parseInt
method belongs to the whole Integer
class, not to any particular instance of the Integer
class. . . . To call the static parseInt
method, you use the Integer
class’s name along with a dot. You write something like Integer.parseInt(reply)
.
That’s very nice! How about the System.out
business that I introduce in Chapter 3? I can apply my quotation to that, too.
The static out
variable belongs to the whole System
class, not to any particular instance of the System
class. . . . To refer to the static out
variable, you use the System
class’s name along with a dot. You write something like System.out.println()
.
If you think about what System.out
means, this static business makes sense. After all, the name System.out
refers to the place where a Java program sends text output. (When you use Eclipse, the name System.out
refers to Eclipse’s Console view.) A typical program has only one place to send its text output. So a Java program has only one out
variable. No matter how many objects you create — three, ten, or none — you have just one out
variable. And when you make something static, you ensure that the program has only one of those things.
All right, then! The out
variable is static.
To abbreviate the name of a static variable (or a static method), you don’t use an ordinary import declaration. Instead, you use a static import declaration. That’s why, in Chapter 9 and beyond, I use the word static
to import the out
variable:
import static
java.lang.System.out;
Barry makes good on an age-old promise
In Chapter 6, I pull a variable declaration outside of a main
method. I go from code of the kind in Listing 18-8 to code of the kind that’s in Listing 18-9.
Listing 18-8: Declaring a Variable Inside the main Method
class SnitSoft {
public static void main(String args[]) {
double amount = 5.95;
amount = amount + 25.00;
System.out.println(amount);
}
}
Listing 18-9: Pulling a Variable Outside of the main Method
class SnitSoft {
static double amount = 5.95;
public static void main(String args[]) {
amount = amount + 25.00;
System.out.println(amount);
}
}
In Chapter 6, I promise to explain why Listing 18-9 needs the extra word static
(in static double amount = 5.95
). Well, with all the fuss about static methods in this chapter, I can finally explain everything.
Refer to Figure 18-7. In that figure, you have checks, and you have a sort
method. Each individual check has its own number
, its own amount
, and its own payee
. But the entire Check
class has just one sort
method.
I don’t know about you, but to sort my cancelled checks, I hang them on my exotic Yucca Elephantipes tree. I fasten the higher numbered checks to the upper leaves and put the lower numbered checks on the lower leaves. When I find a check whose number comes between two other checks, I select a free leaf (one that’s between the upper and lower leaves).
A program to mimic my sorting method looks something like this:
class Check {
int number;
double amount;
String payee;
static void sort() {
Yucca tree;
if (myCheck.number > 1700) {
tree.attachHigh(myCheck);
}
// ...
etc.
}
}
Because of the word static
, the Check
class has only one sort
method. And because I declare the tree
variable inside the static sort
method, this program has only one tree
variable. (Indeed, I hang all my cancelled checks on just one Yucca tree.) I can move the tree
variable’s declaration outside of the sort method. But if I do, I may have too many Yucca trees.
class Check {
int number;
double amount;
String payee;
Yucca tree; //This is bad!
//Each check has its own tree.
static
void sort() {
if (myCheck.number > 5000) {
tree.attachHigh(myCheck);
}
// ...
etc.
}
}
In this nasty code, each check has its own number, its own amount, its own payee, and its own tree. But that’s ridiculous! I don’t want to fasten each check to its own Yucca tree. Everybody knows you’re supposed to sort checks with just one Yucca tree. (That’s the way the big banks do it.)
When I move the tree
variable’s declaration outside of the sort
method, I want to preserve the fact that I have only one tree. (To be more precise, I have only one tree for the entire Check
class.) To make sure that I have only one tree, I declare the tree
variable to be static.
class Check {
int number;
double amount;
String payee;
static
Yucca tree; //That’s better!
static
void sort() {
if (myCheck.number > 5000) {
tree.attachHigh(myCheck);
}
// ...
etc.
}
}
For exactly the same reason, I write static
double amount
when I move from Listing 18-8 to 18-9.