Chapter 8
IN THIS CHAPTER
Working with characters
Dealing with “true” or “false” values
Rounding out your knowledge of Java’s primitive types
I don’t particularly like fax machines. They’re so inefficient. Send a short fax, and what do you have? You have two slices of a tree — one at the sending end and another at the receiving end. You also have millions of dots — dots that scan tiny little lines across the printed page. The dots distinguish patches of light from patches of darkness. What a waste!
Compare a fax with an email message. Using email, I can send a 25-word contest entry with just 2,500 zeros and ones, and I don’t waste any paper. Best of all, an email message doesn’t describe light dots and dark dots. An email message contains codes for each of the letters — a short sequence of zeros and ones for the letter A, a different sequence of zeros and ones for the letter B, and so on. What could be simpler?
Now imagine sending a one-word fax. The word is true, which is understood to mean, “True, I accept your offer to write Beginning Programming with Java For Dummies, 5th Edition.” A fax with this message sends a picture of the four letters t-r-u-e, with fuzzy lines where dirt gets on the paper and little white dots where the cartridge runs short on toner.
But really, what’s the essence of the “true” message? There are just two possibilities, aren’t there? The message could be “true” or “false,” and to represent those possibilities, I need very little fanfare. How about 0 for “false” and 1 for “true?”
They ask, “Do you accept our offer to write Beginning Programming with Java For Dummies, 5th Edition?”
“1,” I reply.
Too bad I didn’t think of that a few months ago. Anyway, this chapter deals with letters, truth, falsehood, and other such things.
In Chapters 6 and 7, you store numbers in all your variables. That’s fine, but there’s more to life than numbers. For example, I wrote this book with a computer, and this book contains thousands and thousands of nonnumeric things called characters.
The Java type that’s used to store characters is char. Listing 8-1 has a simple program that uses the char
type, and a run of the Listing 8-1 program is shown in Figure 8-1.
LISTING 8-1 Using the char Type
class LowerToUpper {
public static void main(String args[]) {
char smallLetter, bigLetter;
smallLetter = ’b’;
bigLetter = Character.toUpperCase(smallLetter);
System.out.println(bigLetter);
}
}
In Listing 8-1, the first assignment statement stores the letter b
in the smallLetter
variable. In that statement, notice how b
is surrounded by single quote marks (’ ’
). In a Java program, every char
literal starts and ends with a single quote mark.
In the second assignment statement of Listing 8-1, the program calls an API method whose name is Character.toUpperCase
. The method Character.toUpperCase
does what its name suggests — the method produces the uppercase equivalent of a lowercase letter. In Listing 8-1, this uppercase equivalent (the letter B
) is assigned to the variable bigLetter
, and the B
that’s in bigLetter
is printed on the screen, as illustrated in Figure 8-2.
A while ago, I wondered what would happen if I called the Character.toUpperCase
method and fed the method a character that isn’t lowercase to begin with. I yanked out the Java API documentation, but I found no useful information. The documentation said that toUpperCase
“converts the character argument to uppercase using case mapping information from the UnicodeData file.” Thanks, but that’s not useful to me.
Silly as it seems, I asked myself what I’d do if I were the toUpperCase
method. What would I say if someone handed me a capital R
and told me to capitalize that letter? I’d say, “Take back your stinking capital R
.” In the lingo of computing, I’d send that person an error message. So I wondered whether I’d get an error message if I applied Character.toUpperCase
to the letter R
.
I tried it. I cooked up the experiment in Listing 8-2.
LISTING 8-2 Investigating the Behavior of toUpperCase
class MyExperiment {
public static void main(String args[]) {
char smallLetter, bigLetter;
smallLetter = ’R’;
bigLetter = Character.toUpperCase(smallLetter);
System.out.println(bigLetter);
smallLetter = ’3’;
bigLetter = Character.toUpperCase(smallLetter);
System.out.println(bigLetter);
}
}
In my experiment, I didn’t mix chemicals and blow things up. Here’s what I did instead:
I assigned ’R’ to smallLetter
.
The toUpperCase
method took the uppercase R
and gave me back another uppercase R
. (See Figure 8-3.) I got no error message. This told me what the toUpperCase
method does with a letter that’s already uppercase. The method does nothing.
I assigned ’3’
to smallLetter
.
The toUpperCase
method took the digit 3
and gave me back the same digit 3
. (See Figure 8-3.) I got no error message. This told me what the toUpperCase
method does with a character that’s not a letter. It does nothing — zip, zilch, bupkis.
I write about this experiment to make an important point. When you don’t understand something about computer programming, it often helps to write a test program. Make up an experiment and see how the computer responds.
I guessed that handing a capital R
to the toUpperCase
method would give me an error message, but I was wrong. See? The answers to questions aren’t handed down from heaven. The people who created the Java API made decisions. They made some obvious choices, and they also made some unexpected choices. No one knows everything about Java’s features, so don’t expect to cram all the answers into your head.
The Java documentation is great, but for every question that the documentation answers, it ignores three other questions. So be bold. Don’t be afraid to tinker. Write lots of short, experimental programs. You can’t break the computer, so play tough with it. Your inquisitive spirit will always pay off.
Reading and understanding Java’s API documentation is an art, not a science. For advice on making the most of these docs, read my article “Making Sense of Java’s API Documentation,” at www.dummies.com/programming/java/making-sense-of-javas-api-documentation
.
A char
variable stores only one character. So if you’re tempted to write the following statements
char smallLetters;
smallLetters = ’barry’; //Don’t do this
please resist the temptation. You can’t store more than one letter at a time in a char
variable, and you can’t put more than one letter between a pair of single quotes. If you’re trying to store words or sentences (not just single letters), then you need to use something called a String. For a look at Java’s String
type, see Chapter 18.
In Listing 8-2, I use smallLetter
twice, and I use bigLetter
twice. That’s why they call these things variables. First, the value of smallLetter
is R
. Later, I vary the value of smallLetter
so that the value of smallLetter
becomes 3
.
When I assign a new value to smallLetter
, the old value of smallLetter
gets obliterated. For example, in Figure 8-4, the second smallLetter
assignment puts 3
into smallLetter
. When the computer executes this second assignment statement, the old value R
is gone.
Is that okay? Can you afford to forget the value that smallLetter
once had? Yes, in Listing 8-2, it’s okay. After you’ve assigned a value to bigLetter
with the statement
bigLetter = Character.toUpperCase(smallLetter);
you can forget all about the existing smallLetter
value. You don’t need to do this:
// This code is cumbersome.
// The extra variables are unnecessary.
char smallLetter1, bigLetter1;
char smallLetter2, bigLetter2;
smallLetter1 = ’R’;
bigLetter1 = Character.toUpperCase(smallLetter1);
System.out.println(bigLetter1);
smallLetter2 = ’3’;
bigLetter2 = Character.toUpperCase(smallLetter2);
System.out.println(bigLetter2);
You don’t need to store the old and new values in separate variables. Instead, you can reuse the variables smallLetter
and bigLetter
as in Listing 8-2.
This reuse of variables doesn’t save you from a lot of extra typing. It doesn’t save much memory space, either. But reusing variables keeps the program uncluttered. When you look at Listing 8-2, you can see at a glance that the code has two parts, and you see that both parts do roughly the same thing.
The code in Listing 8-2 is simple and manageable. In such a small program, simplicity and manageability don’t matter much. But in a large program, it helps to think carefully about the use of each variable.
The previous section discusses the reuse of variables to make a program slick and easy to read. This section shows you the flip side. In this section, the problem at hand forces you to create new variables.
Suppose that you’re writing code to reverse the letters in a four-letter word. You store each letter in its own, separate variable. Listing 8-3 shows the code, and Figure 8-5 shows the code in action.
LISTING 8-3 Making a Word Go Backward
import java.util.Scanner;
class ReverseWord {
public static void main(String args[]) {
Scanner keyboard = new Scanner(System.in);
char c1, c2, c3, c4;
c1 = keyboard.findWithinHorizon(".", 0).charAt(0);
c2 = keyboard.findWithinHorizon(".", 0).charAt(0);
c3 = keyboard.findWithinHorizon(".", 0).charAt(0);
c4 = keyboard.findWithinHorizon(".", 0).charAt(0);
System.out.print(c4);
System.out.print(c3);
System.out.print(c2);
System.out.print(c1);
System.out.println();
keyboard.close();
}
}
The trick in Listing 8-3 is as follows:
c1
, c2
, c3
, and c4
in that order.c4
, c3
, c2
, and then c1
, as illustrated in Figure 8-6.If you don’t use four separate variables, you don’t get the result that you want. For example, imagine that you store characters in only one variable. You run the program and type the word pots
. When it’s time to display the word in reverse, the computer remembers the final s
in the word pots
. But the computer doesn’t remember the p
, the o
, or the t
, as shown in Figure 8-7.
I wish I could give you 12 simple rules to help you decide when and when not to reuse variables. The problem is, I can’t. It all depends on what you’re trying to accomplish. So, how do you figure out on your own when and when not to reuse variables? Like the guy says to the fellow who asks how to get to Carnegie Hall, “Practice, practice, practice.”
The people who created Java’s Scanner
class didn’t create a next
method for reading a single character. So, to input a single character, I paste two Java API methods together. I use the findWithinHorizon
and charAt
methods.
Table 5-1 (over in Chapter 5) introduces this findWithinHorizon(".", 0).charAt(0)
technique for reading a single input character, and Listing 8-3 uses the technique to read one character at a time. (In fact, Listing 8-3 uses the technique four times to read four individual characters.)
Notice the format for the input in Figure 8-5. To enter the characters in the word pots
, I type four letters, one after another, with no blank spaces between the letters and no quote marks. The findWithinHorizon(".", 0).charAt(0)
technique works that way, but don’t blame me or my technique. Other developers’ character-reading methods work the same way. No matter whose methods you use, reading a character differs from reading a number. Here’s how:
With methods like nextDouble
and nextInt
, you type blank spaces between numbers.
If I type 80 6, then two calls to nextInt
read the number 80
, followed by the number 6
. If I type 806, then a single call to nextInt
reads the number 806
(eight hundred six), as illustrated in Figure 8-8.
With findWithinHorizon(".", 0).charAt(0)
, you don’t type blank spaces between characters.
If I type po, then two successive calls to findWithinHorizon(".", 0).charAt(0)
read the letter p
, followed by the letter o
. If I type p o, then two calls to findWithinHorizon(".", 0).charAt(0)
read the letter p
, followed by a blank space character. (Yes, the blank space is a character!) Again, see Figure 8-8.
Write a program that reads three letters from the keyboard and outputs all possible arrangements of the three letters. For example, if the program reads the letters
box
the program outputs
box
bxo
obx
oxb
xbo
xob
I’m in big trouble. I have 140 gumballs, and 15 kids are running around and screaming in my living room. They’re screaming because each kid wants 10 gumballs, and they’re running because that’s what kids do in a crowded living room. I need a program that tells me whether I can give 10 gumballs to each kid.
I need a variable of type boolean. A boolean
variable stores one of two values — true
or false
(true
, I can give ten gumballs to each kid; or false
, I can’t give ten gumballs to each kid). Anyway, the kids are going berserk, so I’ve written a short program and put it in Listing 8-4. The output of the program is shown in Figure 8-9.
LISTING 8-4 Using the boolean Type
class CanIKeepKidsQuiet {
public static void main(String args[]) {
int gumballs;
int kids;
int gumballsPerKid;
boolean eachKidGetsTen;
gumballs = 140;
kids = 15;
gumballsPerKid = gumballs / kids;
System.out.print("True or false? ");
System.out.println("Each kid gets 10 gumballs.");
eachKidGetsTen = gumballsPerKid >= 10;
System.out.println(eachKidGetsTen);
}
}
In Listing 8-4, the variable eachKidGetsTen
is of type boolean
. So the value stored in the eachKidGetsTen
variable can be either true
or false
. (I can’t store a number or a character in the eachKidGetsTen
variable.)
To find a value for the variable eachKidGetsTen
, the program checks to see whether gumballsPerKid
is greater than or equal to ten. (The symbols >=
stand for “greater than or equal to.” What a pity! There’s no ≥ key on the standard computer keyboard.) Because gumballsPerKid
is only nine, gumballsPerKid >= 10
is false. So eachKidGetsTen
becomes false
. Yikes! The kids will tear the house apart! (Before they do, take a look at Figure 8-10.)
In Listing 8-4, the code gumballsPerKid >= 10
is an expression. The expression’s value depends on the value stored in the variable gumballsPerKid
. On a bad day, the value of gumballsPerKid >= 10
is false
. So the variable eachKidGetsTen
is assigned the value false
.
An expression like gumballsPerKid >= 10
, whose value is either true
or false
, is sometimes called a condition.
In Listing 8-4, I compare a variable’s value with the number 10. I use the
operator in the expression >=
gumballsPerKid >= 10
Of course, the greater-than-or-equal-to comparison gets you only so far. Table 8-1 shows you the operators you can use to compare things with one another.
TABLE 8-1 Comparison Operators
Operator Symbol | Meaning | Example |
| is equal to |
|
| is not equal to |
|
| is less than |
|
| is greater than |
|
| is less than or equal to |
|
| is greater than or equal to |
|
With the operators in Table 8-1, you can compare both numbers and characters.
You can compare other things (besides numbers and characters) with the
and ==
operators. But when you do, you have to be careful. For more information, see Chapter 18.!=
Nothing is more humdrum than comparing numbers. “True or false? Five is greater than or equal to ten.” False. Five is neither greater than nor equal to ten. See what I mean? Bo-ring.
Comparing whole numbers is an open-and-shut case. But unfortunately, when you compare decimal numbers, there’s a wrinkle. Take a program for converting from Celsius to Fahrenheit. Wait! Don’t take just any such program; take the program in Listing 8-5.
LISTING 8-5 It’s Warm and Cozy in Here
import java.util.Scanner;
class CelsiusToFahrenheit {
public static void main(String args[]) {
Scanner keyboard = new Scanner(System.in);
double celsius, fahrenheit;
System.out.print("Enter the Celsius temperature: ");
celsius = keyboard.nextDouble();
fahrenheit = 9.0 / 5.0 * celsius + 32.0;
System.out.print("Room temperature? ");
System.out.println(fahrenheit == 69.8);
keyboard.close();
}
}
If you run the code in Listing 8-5 and input the number 21, the computer finds the value of 9.0 / 5.0 * 21 + 32.0
. Believe it or not, you want to check the computer’s answer. (Who knows? Maybe the computer gets it wrong!) You need to do some arithmetic, but please don’t reach for your calculator. A calculator is just a small computer, and machines of that kind stick up for one another. To check the computer’s work, you need to do the arithmetic by hand. What? You say you’re math-phobic? Well, don’t worry. I’ve done all the math in Figure 8-11.
If you do the arithmetic by hand, the value you get for 9.0 / 5.0 * 21 + 32.0
is exactly 69.8. So run the code in Listing 8-5 and give celsius
the value 21
. You should get true
when you display the value of fahrenheit == 69.8
, right?
Well, no. Take a look at the run in Figure 8-12. When the computer evaluates fahrenheit == 69.8
, the value turns out to be false
, not true
. What’s going on here?
A little detective work can go a long way. Review the facts:
fahrenheit
should be exactly 69.8
.fahrenheit
is 69.8
, then fahrenheit == 69.8
is true
.false
. So the expression fahrenheit == 69.8
isn’t true
.How do you reconcile these facts? There can be little doubt that fahrenheit == 69.8
is false
, so what does that say about the value of fahrenheit
? Nowhere in Listing 8-5 is the value of fahrenheit
displayed. Could that be the problem?
At this point, I use a popular programmer’s trick. I add statements to display the value of fahrenheit
:
fahrenheit = 9.0 / 5.0 * celsius + 32.0;
System.out.print("fahrenheit: "); //Added
System.out.println(fahrenheit); //Added
A run of the enhanced code is shown in Figure 8-13. As you can see, the computer misses its mark. Instead of the expected value 69.8
, the computer’s value for 9.0 / 5.0 * 21 + 32.0
is 69.80000000000001
. That’s just the way the cookie crumbles. The computer does all its arithmetic with zeros and ones, so the computer’s arithmetic doesn’t look like the base-10 arithmetic in Figure 8-11. The computer’s answer isn’t wrong. The answer is just slightly inaccurate.
In an example in Chapter 7, Java’s remainder operator (%
) gives you the answer 0.1299999999999999
instead of the 0.13
that you expect. The same strange kind of thing happens in this section’s example. But this section’s code doesn’t use an exotic remainder operator. This section’s code uses your old friends: division, multiplication, and addition.
Be careful when you compare two numbers for equality (with
) or for inequality (==
with
). Little inaccuracies can creep in almost anywhere when you work with Java’s !=
double
type or with Java’s float
type. And several little inaccuracies can build on one another to become very large inaccuracies. When you compare two double
values or two float
values, the values are almost never dead-on equal to one another.
The comparison operators in Table 8-1 work overtime for characters. Roughly speaking, the operator
means “comes earlier in the alphabet.” But you have to be careful of the following: <
B
comes alphabetically before H
, the condition ’B’ < ’H’
is true
. That’s not surprising.b
comes alphabetically before h
, the condition ’b’ < ’h’
is true
. That’s no surprise, either.’b’ < ’H’
is false
. Now, that’s a surprise. (See Figure 8-14.)In practice, you seldom have reason to compare one letter with another. But in Chapter 18, you can read about Java’s String
type. With the String
type, you can compare words, names, and other good stuff. At that point, you have to think carefully about alphabetical ordering, and the ideas in Figure 8-14 come in handy.
In Chapter 7, I tell you that Java has eight primitive types, but Table 7-1 lists only six of eight types. Table 8-2 describes the remaining two types — the types char
and boolean
. Table 8-2 isn’t too exciting, but I can’t just leave you with the incomplete story in Table 7-1.
TABLE 8-2 Java’s Primitive Non-Numeric Types
Type Name | Range of Values |
Character Type | |
| Thousands of characters, glyphs, and symbols |
Logical Type | |
| Only |
jshell> Character.isDigit(’a’)
jshell> Character.isDigit(’2’)
jshell> Character.isLetter(’a’)
jshell> Character.isLetter(’2’)
jshell> Character.isLetterOrDigit(’4’)
jshell> Character.isLetterOrDigit(’@’)
jshell> Character.isLowerCase(’b’)
jshell> Character.isLowerCase(’B’)
jshell> Character.isLowerCase(’7’)
jshell> Character.isJavaIdentifierPart(’x’)
jshell> Character.isJavaIdentifierPart(’7’)
jshell> Character.isJavaIdentifierPart(’-’)
jshell> Character.isJavaIdentifierPart(’ ’)
52.14.240.252