Chapter 3
In This Chapter
Making decisions with Java statements
Repeating actions with Java statements
Adding exception handling
Human thought centers on nouns and verbs. Nouns are the “stuff,” and verbs are the stuff’s actions. Nouns are the pieces, and verbs are the glue. Nouns are, and verbs do. When you use nouns, you say, “book,” “room,” or “stuff.” When you use verbs, you say “Do this,” “Do that,” “Hoist that barge,” or “Lift that bale.”
Java also has nouns and verbs. Java’s nouns include String
, ArrayList
, and JFrame
, along with Android-specific things such as Activity
, Application
, and Bundle
. Java’s verbs involve assigning values, choosing among alternatives, repeating actions, and other courses of action.
This chapter covers some of Java’s verbs. In Chapter 4 of this minibook, you bring in the nouns.
When you’re writing computer programs, you’re constantly hitting forks in roads. Did the user correctly type his or her password? If yes, let the user work; if no, kick the bum out. So the Java programming language needs a way of making a program branch in one of two directions. Fortunately, the language has a way: It’s called an if
statement. The use of an if
statement is illustrated in Listing 3-1.
Listing 3-1: A Method with an if Statement
public void onClick(View v) {
if (((CheckBox) v).isChecked()) {
textview.setTextColor(Color.GREEN);
textview.setText("Thank you!");
} else {
textview.setTextColor(Color.RED);
textview.setText("No harm done.");
}
}
Android calls the onClick
method in Listing 3-1 when the user clicks a particular check box. (Android uses the parameter v
to pass this check box to the onClick
method. That’s how the onClick
method finds out which object the user clicked.) If clicking puts a check mark in the check box, the text view displays Thank you!
in green letters. Otherwise, the text view displays No harm done.
in red letters. (See the colorless Figure 3-1.)
Figure 3-1: Checking and unchecking in Listing 3-1.
An if
statement has the following form:
if (condition) {
statements to be executed when the condition is true
} else {
statements to be executed when the condition is false
}
In Listing 3-1, the condition being tested is
((CheckBox) v).isChecked()
In this condition, variable v
is the onClick
method’s parameter — the thing that Android passes to the onClick
method. Listing 3-1 is far from being a complete Android app. But presumably, v
is a check box. (See the sidebar, “Central casting.”)
Android’s isChecked
method returns either true
or false
— true
when the v
check box is checked; false
when the v
check box isn’t checked.
The condition in an if
statement must be enclosed within parentheses. The condition must be a boolean
expression — an expression whose value is either true
or false
. (See Chapter 2 of this minibook for information about Java’s primitive types, including the boolean
type.) So, for example, the following condition is okay:
if (numberOfTries < 17) {
But the strange kind of condition that you can use in languages, such as C++, is not okay:
if (17) { //This is incorrect.
You can omit curly braces when only one statement comes between the condition and the word else
. You can also omit braces when only one statement comes after the word else
. For example, the following code is okay:
if (((CheckBox) v).isChecked())
textview.setText("Thank you!");
else {
textview.setTextColor(Color.RED);
textview.setText("No harm done.");
}
An if
statement can also enjoy a full and happy life without an else
part. So the following code forms a complete if
statement:
if (((CheckBox) v).isChecked()) {
textview.setTextColor(Color.GREEN);
textview.setText("Thank you!");
}
Java has several ways to test for equality (“Is this value the same as that value?”). None of these ways is the first thing you’d think of doing. In particular, to find out whether the parameter v
is the thing you call checkbox1
, you don’t write if (v = checkbox1)
. Instead, you use a double equal sign (==
). You write if (v == checkbox1)
. In Java, the single equal sign (=
) is reserved for assignment. So n = 5
means “Let n
stand for the value 5
,” and v = checkbox1
means “Let v
stand for the checkbox1
object.”
Comparing two strings is yet another story. When you compare two strings with one another, you don’t want to use the double equal sign. Using the double equal sign would ask, “Is this string stored in exactly the same place in memory as that other string?” That’s usually not what you want to ask. Instead, you usually want to ask, “Does this string have the same characters in it as that other string?” To ask the second question (the more appropriate question), Java’s String
type has a method named equals
:
if (response.equals("yes")) {
The equals
method compares two strings to see whether they have the same characters in them. In this paragraph’s tiny example, the variable response
refers to a string, and the text "yes"
refers to a string. The condition response.equals("yes")
is true if response
refers to a string whose letters are ‘y’, then ‘e’, and then ‘s’.
I’m the first to admit that I hate making decisions. If things go wrong, I would rather have the problem be someone else’s fault. Writing the previous sections (on making decisions with Java’s if
statement) knocked the stuffing right out of me. That’s why my mind boggles as I begin this section on choosing among many alternatives.
Consider the code in Listing 3-2.
Listing 3-2: A Java switch Statement
public void onClick(View v) {
String message;
Editable edit = textfield.getText();
if (edit.length() != 0) {
int number =
Integer.valueOf(edit.toString());
switch (number) {
case 0:
message = "none";
break;
case 1:
message = "one";
break;
case 2:
message = "two";
break;
case 3:
message = "three";
break;
default:
message = "many";
}
label.setText(message);
}
}
The code in Listing 3-2 is part of an app, and the app’s screen is pictured in Figure 3-2.
Figure 3-2: A TextView object reports on an EditText object’s content.
The user clicks something or other (something not specified in Listing 3-2 or in Figure 3-2). As a result of the user’s click, Android does the stuff in Listing 3-2. Some of that stuff involves a Java switch
statement. The switch
statement examines the characters in a text field. (In Figure 3-2, the text field contains 011
.) To make sure that the text field characters are all digits, I included the following element in the app’s layout document:
<EditText android:layout_height="wrap_content"
android:id="@+id/editText1"
android:layout_width="match_parent"
android:inputType="number"></EditText>
In the first line of the switch
statement, number
is a whole number. If number
is 0
, the code makes message
be "none"
. If number
is 1
, the code makes message
be "one"
. If number
is not 0
, 1
, 2
, or 3
, the default
part of the switch
statement takes over, and the code makes message
be "many"
.
Each break
statement in Listing 3-2 says, “Jump past any remaining cases.” You can omit a break
statement, but do so at your own peril! For example, if you write
case 2:
message = "two";
case 3:
message = "three";
default:
message = "many";
}
and number
is 2
, Java executes three cases, one after another — namely, message = "two"
followed by message = "three"
followed immediately by message = "many"
. The lack of break
statements tells Java to fall-through from one case to the next. The end result is that the message is "many"
, and that’s probably not what you want.
A switch
statement has the following form:
switch (expression) {
case constant1:
statements to be executed when the
expression has value constant1
case constant2:
statements to be executed when the
expression has value constant2
case …
default:
statements to be executed when the
expression has a value different from
any of the constants
}
You can’t put any old expression in a switch
statement. The expression that’s tested at the start of a switch
statement must have
char
, byte
, short
, or int
, orCharacter
, Byte
, Short
, or Integer
, orenum
typeAn enum
type is a type whose values are limited to the few that you declare. For example, the code
enum TrafficSignal {GREEN, YELLOW, RED};
defines a type whose only values are GREEN
, YELLOW
, and RED
. Elsewhere in your code, you can write
TrafficSignal signal;
signal = TrafficSignal.GREEN;
to make use of the TrafficSignal
type.
String myString = "one";
// …
// Set the value of myString here
// …
switch (myString) {
case "one":
textView.setText("1");
break;
case "two":
textView.setText("2");
break;
default:
break;
}
In 1966, the company that brings you Head & Shoulders shampoo made history. On the back of the bottle, the directions for using the shampoo read, “Lather, rinse, repeat.” Never before had a complete set of directions (for doing anything, let alone shampooing your hair) been summarized so succinctly. People in the direction-writing business hailed this as a monumental achievement. Directions like these stood in stark contrast to others of the time. (For instance, the first sentence on a can of bug spray read, “Turn this can so that it points away from your face.” Duh!)
Aside from their brevity, the thing that made the Head & Shoulders directions so cool was that, with three simple words, they managed to capture a notion that’s at the heart of all instruction-giving — the notion of repetition. That last word, repeat, took an otherwise bland instructional drone and turned it into a sophisticated recipe for action.
The fundamental idea is that when you’re following directions, you don’t just follow one instruction after another. Instead, you take turns in the road. You make decisions (“If HAIR IS DRY, then USE CONDITIONER”), and you go into loops (“LATHER-RINSE and then LATHER-RINSE again”). In application development, you use decision-making and looping all the time.
In an Android app, a content provider feeds a cursor to your code. You can think of the cursor as a pointer to a row in a table. In Listing 3-3, each table row has three entries — an _id
, a name
, and an amount
. Supposedly, the _id
uniquely identifies a row, the name
is a person’s name, and the amount
is a huge number of dollars owed to you by that person.
Listing 3-3: A while Loop
cursor.moveToFirst();
while (!cursor.isAfterLast()) {
String _id = cursor.getString(0);
String name = cursor.getString(1);
String amount = cursor.getString(2);
textViewDisplay.append(_id + " " + name + " " + amount + "
");
cursor.moveToNext();
}
A cursor’s moveToFirst
method makes the cursor point to the first row of the table. Regardless of the row a cursor points to, the cursor’s moveToNext
method makes the cursor point to the next row of the table. The cursor’s isAfterLast
method returns true
when, having tried to move to the next row, there’s no next row.
In Java, an exclamation point (!
) means “not,” so while (!cursor.isAfterLast())
means “while it’s not true that the cursor has reached past the table’s last row …” So the loop in Listing 3-3 repeatedly does the following:
As long as the cursor has not reached past the last row,
get the string in the row’s initial column and
make _id refer to that string,
get the string in the row’s middle column and
make name refer to that string,
get the string in the row’s last column and
make amount refer to that string, and
append these strings to the textViewDisplay, and then
move the cursor to the next row in preparation
for returning to the top of the while statement.
Imagine that a particular cursor’s table has 100 rows. Then a processor executes the statements inside Listing 3-3's while
loop 100 times. Using the official developer lingo, the processor performs 100 loop iterations.
A while
statement has the following form:
while (condition) {
statements to be executed
}
You can omit the curly braces when the loop has only one statement to be executed.
Life is filled with examples of counting loops. And app development mirrors life — or is it the other way around? When you tell a device what to do, you’re often telling the device to display three lines, process ten accounts, dial a million phone numbers, or whatever.
Listing 3-3 displays all the rows in a table full of data. Sometimes, all the data is too much data. To get the idea of what the table has to offer, you might want to display only the first ten rows of data. The code in Listing 3-4 does the job.
Listing 3-4: A for Loop
cursor.moveToFirst();
for (int i = 0; i < 10; i++) {
String _id = cursor.getString(0);
String name = cursor.getString(1);
String amount = cursor.getString(2);
textViewDisplay.append(i + ": " + _id + " " + name + " " + amount + "
");
cursor.moveToNext();
}
Listing 3-4 declares an int
variable named i
. The starting value of i
is 0
. As long as the condition i < 10
is true, the processor executes the instructions inside the for
statement. In this example, the for
statement’s instructions include getting an _id
, getting a name
, getting an amount
, and appending all that stuff to the textViewDisplay
. In addition to that stuff, the textViewDisplay
gets the value of i
(be it 0
, 1
, 2
, or any number less than 10
).
To keep the ball rolling, the last instruction in the for
statement moves the cursor to the next line. But wait! What happens when the processor goes to the beginning of the loop again? Before starting the loop anew, the processor does i++
, which is Java-speak for “Add 1 to i
.” So after ten loop iterations, the value of i
finally reaches 10
and the execution of the for
loop’s instructions comes to an end.
A for
statement has the following form:
for (initialization ; condition ; update) {
statements to be executed
}
int i = 0
in Listing 3-4) defines the action to be taken before the first loop iteration.i < 10
in Listing 3-4) defines the thing to be checked before an iteration. If the condition is true
, the processor executes the iteration. If the condition is false
, the processor doesn’t execute the iteration and moves on to execute whatever code comes after the for
statement.i++
in Listing 3-4) defines an action to be taken at the end of each loop iteration.As always, you can omit the curly braces when the loop has only one statement to be executed.
Like the protagonist in an ancient Greek tragedy, the loop in Listing 3-4 has a fatal flaw. The loop comes crashing down if the cursor’s table has fewer than ten rows. To remedy this (and to save the protagonist), you can add a check for “rowlessness” inside the loop:
for (int i = 0; i < 10; i++) {
if (cursor.isAfterLast()) {
break;
}
String _id = cursor.getString(0);
String name = cursor.getString(1);
String amount = cursor.getString(2);
textViewDisplay.append(i + ": " + _id + " " + name + " " + amount + "
");
cursor.moveToNext();
}
The if
statement says “If there are no more rows (because the cursor is already positioned after the last row) then execute the break
statement.” And inside a loop (a while
loop, a for
loop, or some other kind of loop), a break
statement says, “This looping is done” and “We’re outta here.” The processor moves on to execute whatever statement comes immediately after the loop’s code.
To find a particular row of a cursor’s table, you normally do a query. (For straight talk about queries, see Book IV.) You almost never perform a do-it-yourself search through a table’s data. But just this once, look at a loop that iterates through row after row — the loop is in Listing 3-5.
Listing 3-5: Leap Before You Look
cursor.moveToFirst();
String name;
do {
String _id = cursor.getString(0);
name = cursor.getString(1);
String amount = cursor.getString(2);
textViewDisplay.append(_id + " " + name + " " + amount + "
");
cursor.moveToNext();
} while (!name.equals("Burd") && !cursor.isAfterLast());
With a do
loop, the processor jumps right in, takes action, and then checks a condition to see whether the result of the action is what you want. If the result is what you want, execution of the loop is done. If not, the processor goes back to the top of the loop for another go-around.
In Listing 3-5, you’re looking for a row with the name Burd. (After all, the bum owes you lots of money.) When you enter the loop, the cursor points to the table’s first row. Before checking a row for the name Burd, you fetch that first row’s data and add the data to the textViewDisplay
where the user can see what’s going on.
Before you march on to the next row (the next loop iteration), you check a condition to make sure that another row is worth visiting. (Check to make sure that you haven’t yet found that Burd guy, and that you haven’t moved past the last row of the table.)
An array is a bunch of values of the same type. Each value in the array is associated with an index. For example, the following code puts 15.020999999999999 in an app’s textView1
:
double[] measurements = new double[3];
measurements[0] = 5.7;
measurements[1] = 9.32;
measurements[2] = 0.001;
textView1.setText(Double.toString(measurements[0]
+ measurements[1] + measurements[2]));
The following code puts Barry Burd and Jane Dough in an app’s textView1
:
String[] names = new String[3];
names[0] = new String("Barry Burd");
names[1] = new String("John Public");
names[2] = new String("Jane Dough");
textView1.setText(names[0] + " and " + names[2]);
You can step from value to value in an array using a for
loop. For example, the following code puts Barry Burd John Public Jane Dough in an app’s textView1
:
String[] names = new String[3];
names[0] = new String("Barry Burd ");
names[1] = new String("John Public ");
names[2] = new String("Jane Dough ");
textView1.setText("");
for (int i = 0; i < 3; i++) {
textView1.append(names[i]);
}
In the mid-1960s, a company advertised its product by announcing, “Our product used to be perfect. But now, our product is even better!”
In the mid-2000s, the newly created Java 5 specification had a brand-new kind of loop. This feature has been part of Java for several years, but it’s still called the enhanced for
loop. The following code uses an enhanced for
loop to put Barry Burd John Public Jane Dough in an app’s textView1
:
String[] names = new String[3];
names[0] = new String("Barry Burd ");
names[1] = new String("John Public ");
names[2] = new String("Jane Dough ");
textView1.setText("");
for (String s : names) {
textView1.append(s);
}
Here’s another example. Suppose you have a cursor, and the cursor points to a table’s row. (To keep this example simple, I assume that each column contains String
data.) You don’t know the table’s column names, and you don’t know how many columns the table has. Java’s enhanced for
statement provides an elegant way to deal with this kind of situation. Listing 3-6 shows you the story.
Listing 3-6: An Enhanced for Loop
cursor.moveToFirst();
while (!cursor.isAfterLast()) {
String[] columnNames = cursor.getColumnNames();
for (String colName : columnNames) {
int index = cursor.getColumnIndex(colName);
textViewDisplay.append(colName + ":" + cursor.getString(index) + ", ");
}
textViewDisplay.append("
");
cursor.moveToNext();
}
In Listing 3-6, a cursor’s getColumnNames
method returns an array of String
values. The code assigns this array to the columnNames
variable. Then the enhanced for
loop creates a variable (colName
) that steps through the String
values in the array. The line
for (String colName : columnNames)
says, “Repeat the instructions in the for
statement once for each of the String
values stored in the columnNames
array. During each value in the array, let the variable colName
stand for that value during one of the loop’s iterations.” So, for example, if the columnNames
array contains the strings _id
, name
, and amount
, the processor performs three iterations of the enhanced loop in Listing 3-6. During the first iteration, colName
stands for "_id"
. During the second iteration, colName
stands for "name"
. During the third iteration, colName
stands for "amount"
.
With or without enhanced loops, a cursor’s getString
method needs a column number. In Listing 3-5 (and in previous listings), I hand column numbers 0, 1, and 2 to the getString
method. In Listing 3-6, I fetch these column numbers from the column names, using the cursor’s getColumnIndex
method.
An enhanced for
statement has the following form:
for (TypeName variable : arrayOrCollection) {
statements to be executed
}
The TypeName
is the type of each element in the arrayOrCollection
. The loop performs an iteration for each element of the arrayOrCollection
. During each iteration, the variable refers to one of the elements in the arrayOrCollection
.
The Java programming language has a mechanism called exception handling. With exception handling, a program can detect that things are about to go wrong and respond by creating a brand-new object. In the official terminology, the program is said to be throwing an exception. That new object, an instance of the Exception
class, is passed like a hot potato from one piece of code to another until some piece of code decides to catch the exception. When the exception is caught, the program executes some recovery code, buries the exception, and moves on to the next normal statement as if nothing had ever happened.
The whole thing is done with the aid of several Java keywords. These keywords are as follows:
throw
: Creates a new exception object.throws
: Passes the buck from a method up to whatever code called the method.try
: Encloses code that has the potential to create a new exception object. In the usual scenario, the code inside a try
clause contains calls to methods whose code can create one or more exceptions.catch
: Deals with the exception, buries it, and then moves on.For example, Java’s Integer.parseInt
method turns a String
value into an int
value. The value of "279" + 1
is "2791"
, but the value of Integer.parseInt("279") + 1
is 280. A call to Integer.parseInt
throws a NumberFormat
Exception if the call’s parameter isn’t a whole number. So if your code calls Integer.parseInt("3.5")
, your code has to deal with a NumberFormat
Exception. (The String value "3.5"
doesn’t stand for a whole number.)
Here’s a simple method to add one to a number that’s represented as a String
value:
int increment(String str) {
return Integer.parseInt(str) + 1;
}
If you call increment("985")
, you get 986
. That’s good.
But if you call increment("2.71828")
, your code crashes, and your app stops running. Java leaves clues about the crash in the Logcat tab. The clues (which form a Java stack trace) look something like this:
Exception in thread "main" java.lang.NumberFormatException:
For input string: "2.71828"
at java.lang.NumberFormatException.forInputString
at java.lang.Integer.parseInt
If you add some exception handling code to the increment method, your code keeps running with or without the increment("2.71828")
call.
int increment(String str) {
try {
return Integer.parseInt(str) + 1;
} catch (NumberFormatException e) {
return 0;
}
}
With the try
and catch
in the revised method, Java attempts to evaluate Integer.parseInt(str)
. If evaluation is successful, the method returns Integer.parseInt(str) + 1
. But if str
has a weird value, the call to Integer.parseInt
throws a NumberFormatException
. Fortunately, the revised increment
method catches the NumberFormatException
, returns the value 0
, and continues running without bothering the user.
3.135.197.250