• 沒有找到結果。

Empty Statements, Local Variable Declarations, Assignments, and Method Calls

在文檔中 Java Android Development (頁 79-88)

An empty statement is nothing followed by a semicolon. Although this kind of statement appears to be useless, it is useful, as I will explain when I discuss loop statements.

A local variable declaration introduces a variable into a method’s body or other compound statement. This local variable’s lifetime and scope range from its point of declaration to the end of the compound statement in which it is declared. Only statements appearing after the declaration can access the local variable.

NOTE: A local variable is similar to a parameter in that both kinds of variables only exist during a method’s execution. However, a parameter contains a passed argument, whereas a local variable contains whatever value is necessary to help the method accomplish its task.

This statement is similar to an instance field declaration in that it minimally begins with a type name, continues with an identifier that names the local variable, and ends with a semicolon. By convention, a local variable’s name begins with a lowercase letter.

Furthermore, the first letter of each subsequent word in a multiword local variable name is capitalized.

CAUTION: You cannot declare multiple local variables with the same name in the same scope because the compiler will report an “already defined” error message.

An assignment is a close relative of the local variable declaration statement. Instead of starting with a type, this statement begins with the name of a variable that has already been declared, continues with the assignment operator (=) or a compound assignment operator (such as +=), and concludes with an expression and a semicolon.

A method call executes a method, possibly passing arguments and possibly receiving a value in return. Regardless of whether or not a value is returned, a method call is a statement. If you do not assign the method’s return value to a variable, the return value is lost. However, you occasionally might be more interested in what the method accomplishes than in what the method returns.

Listing 2–12’s printBalance() method demonstrates these statements except for empty.

Listing 2–12. Declaring and using local variables in printBalance() void printBalance()

{

int magnitude = (balance < 0) ? -balance : balance;

String balanceRep = (balance < 0) ? "(" : "";

balanceRep += magnitude;

balanceRep += (balance < 0) ? ")" : "";

System.out.println(balanceRep);

}

Listing 2–12 introduces several statements into printBalance() to create a suitable string-based representation of the balance field’s value and output this string. If this value is positive, it is represented and printed as is. If this value is negative, its

magnitude (absolute or positive value) is represented and printed between parentheses.

This listing’s first two statements declare a pair of local variables: magnitude and balanceRep. An expression initializes the magnitude variable to the balance field’s magnitude, whereas another expression initializes balanceRep to "(" or "" (the empty string), depending on whether the balance field’s value is negative or positive.

Unlike fields, which are initialized to default values, and parameters, which are initialized to arguments, local variables are not implicitly initialized. Before you can read a local variable’s value, you must assign a value to the variable. Otherwise, the compiler reports an error about the local variable not having been initialized.

Moving on, two assignment statements follow the local variable declaration statements.

These statements append a string representation of the balance field’s magnitude followed by ")" or "" to balanceRep. Alternatively, I could have expressed the first of these statements as balanceRep = balanceRep + magnitude;.

Listing 2–12 concludes by calling the System.out.println() method to output balanceRep’s character sequence to the standard output device. (Chapter 1 briefly introduces the concept of standard input/output along with System.out.println() and related methods.)

Decisions

Listing 2–12 used the conditional operator to determine whether to assign -balance or balance to magnitude. Although this operator is useful for initializing a variable to one of two values, it cannot be used for choosing between two statements to execute. Java supplies the if-else statement for this purpose.

The if-else statement has the following syntax:

if (Boolean expression) statement1

else

statement2

This statement consists of reserved word if, followed by a Boolean expression in parentheses, followed by a statement to execute (if the Boolean expression evaluates to true), followed by reserved word else, followed by another statement to execute (if the Boolean expression evaluates to false).

Listing 2–13 demonstrates if-else.

Listing 2–13. A revised printBalance() method void printBalance()

{

if (balance < 0)

System.out.println("(" + -balance + ")");

else

System.out.println(balance);

}

Listing 2–13’s if-else statement results in the first System.out.println() method call executing if balance’s value is less than 0, and the second System.out.println() method call executing if balance’s value is greater than or equal to 0.

Each of statement1 and statement2 describes another statement to execute. If you do not need the else part in the preceding syntax, you can omit else and statement2 from the syntax. The resulting statement is called if.

NOTE: When if and if-else are used together, and the source code is not properly indented, it can be difficult to determine which if associates with the else. For example:

if (car.door.isOpen()) if (car.key.isPresent()) car.start();

else car.door.open();

Did the developer intend for the else to match the inner if, but improperly formatted the code to make it appear otherwise? For example:

if (car.door.isOpen()) if (car.key.isPresent()) car.start();

else

car.door.open();

If car.door.isOpen() and car.key.isPresent() each return true, car.start() executes. If car.door.isOpen() returns true and car.key.isPresent() returns false, car.door.open(); executes. Attempting to open an open door makes no sense.

The developer must have wanted the else to match the outer if, but forgot that else matches the nearest if. This problem can be fixed by surrounding the inner if with braces, as follows:

if (car.door.isOpen()) {

if (car.key.isPresent()) car.start();

} else

car.door.open();

When car.door.isOpen() returns true, the compound statement executes. When this method returns false, car.door.open(); executes, which makes sense.

Forgetting that else matches the nearest if and using poor indentation to obscure this fact is known as the dangling-else problem.

You can chain multiple if-else statements together, resulting in the following syntax:

if (Boolean expression1) statement1

else

if (Boolean expression2) statement2

else else

statementN

If the first Boolean expression is true, statement1 executes. Otherwise, if the second Boolean expression is true, statement2 executes. This pattern continues until one of these expressions is true and its corresponding statement executes, or the final else is reached and statementN (the default statement) executes.

Listing 2–14 demonstrates chained if-else.

Listing 2–14. A revised printBalance() method using chained if-else void printBalance()

{

if (balance < 0)

System.out.println("(" + -balance + ")");

else

if (balance == 0)

System.out.println("zero balance");

else

System.out.println(balance);

}

Look closely at Listing 2–14 and you will see that its chained if-else statement is actually an if-else statement, where the statement following the else part (the first else) is another if-else statement.

Chaining if-else statements together leads to verbosity that, in some cases, can be made more concise by using a switch statement. This statement lets you write code for choosing one of several statements to execute, and has the following syntax:

switch (selector expression) {

case value1: statement1 [break;]

case value2: statement2 [break;]

case valueN: statementN [break;]

[default: statement]

}

The switch statement consists of reserved word switch, followed by a selector expression in parentheses, followed by a body of cases. The selector expression is

This book was purchased by [email protected]

typically any expression that evaluates to an integral value. For example, it might evaluate to a 32–bit integer or to a 16-bit character.

Each case begins with reserved word case, continues with a literal value and a colon character (:), continues with a statement to execute, and optionally concludes with a break statement (which I have yet to discuss).

After evaluating the selector expression, switch compares this value with each case’s value until it finds a match. If there is a match, the case’s statement is executed. For example, if the selector expression’s value matches value1, statement1 executes.

The optional break statement (anything placed in square brackets is optional), which consists of reserved word break followed by a semicolon, prevents the flow of execution from continuing with the next case’s statement. Instead, execution continues with the first statement following switch.

NOTE: You will usually place a break statement after a case’s statement. Forgetting to include break can lead to a hard-to-find bug. However, there are situations where you want to group several cases together and have them execute common code. In such a situation, you would omit the break statement from the participating cases.

If none of the cases’ values match the selector expression’s value, and if a default case (signified by the default reserved word followed by a colon) is present, the default case’s statement is executed.

Listing 2–15 demonstrates switch.

Listing 2–15. Using switch to output a compass direction class Compass

{

static final int NORTH = 0;

static final int SOUTH = 1;

static final int WEST = 2;

static final int EAST = 3;

void printDirection(int dir) {

switch (dir) {

case NORTH: System.out.println("You are travelling north."); break;

case SOUTH: System.out.println("You are travelling south."); break;

case EAST : System.out.println("You are travelling east."); break;

case WEST : System.out.println("You are travelling west."); break;

default : System.out.println("Unknown direction");

} } }

Listing 2–15’s Compass class is an example of an enumerated type, a named sequence of related constants. NORTH, SOUTH, EAST, and WEST are Compass’s set of constants.

Java version 5 introduced the enum as an improved enumerated type that overcomes problems with the listing’s form of enumerated type. This feature includes a change to the switch statement, which I will discuss when I cover enums in Chapter 5.

NOTE: Java version 7 introduces the ability to switch on a string-based selector expression. In this situation, each case’s value is a string literal. I will demonstrate this form of the switch statement in the next section.

Loops

It is sometimes necessary to execute a statement repeatedly. This repeated execution is called a loop.

Java provides three kinds of loop statements: for, while, and do-while.

The for statement has the following syntax:

for ([initialize]; [test]; [update]) statement

This statement consists of reserved word for, followed by a header in parentheses, followed by a statement to execute. The header consists of an optional initialization section, followed by an optional test section, followed by an optional update section. A non-optional semicolon separates each of the first two sections from the next section.

The initialization section consists of a comma-separated list of local variable

declarations or variable assignments. Some or all of these variables are typically used to control the loop’s duration, and are known as loop-control variables.

The test section consists of a Boolean expression that determines how long the loop executes. Execution continues as long as this expression evaluates to true.

Finally, the update section consists of a comma-separated list of expressions that typically modify the loop-control variables.

The for statement is perfect for iterating (looping) over an array. Each iteration (loop execution) accesses one of the array’s elements via an array[index] expression, where array is the array whose element is being accessed, and index is the zero-based location of the element being accessed.

Listing 2–16 uses the for statement to iterate over the array of command-line arguments that is passed to the main() method. Each argument is read from the array, and Java version 7’s enhanced switch statement uses the argument to determine a course of action.

Listing 2–16. Using for with switch on a string-based selector expression to process command-line arguments public static void main(String[] args)

{

for (int i = 0; i < args.length; i++) switch (args[i])

{

case "-v":

case "-V": System.out.println("version 1.0");

break;

default : showUsage();

} }

Listing 2–16’s for statement presents an initialization section that declares local variable i, a test section that compares i’s current value to the length of the args array (every array has a length field that returns the number of elements in the array) to ensure that this value is less than the array’s length, and an update section that increments i by 1.

The loop continues until i’s value equals the array’s length.

Each iteration (loop execution) accesses one of the array’s values via the args[i]

expression. This expression returns the array’s ith value (which happens to be a String object in this example). The first value is stored in args[0].

The args[i] expression serves as the switch statement’s selector expression. If this String object contains -V, the second case is executed, which calls

System.out.println() to output a version number message. The subsequent break statement keeps execution from falling into the default case, which calls showUsage() to output usage information when main() is called with unexpected arguments.

If this String object contains -v, the lack of a break statement following the first case causes execution to fall through to the second case, calling System.out.println(). This example demonstrates the occasional need to group cases to execute common code.

The while statement has the following syntax:

while (Boolean expression) statement

This statement consists of reserved word while, followed by a parenthesized Boolean expression header, followed by a statement to repeatedly execute.

The while statement first evaluates the Boolean expression. If it is true, while executes the other statement. Once again, the Boolean expression is evaluated. If it is still true, while re-executes the statement. This cyclic pattern continues.

Prompting the user to enter a specific character is one situation where while is useful.

For example, suppose that you want to prompt the user to enter a specific uppercase letter or its lowercase equivalent. Listing 2–17 provides a demonstration.

Listing 2–17. Prompting the user to enter a specific character via a while statement int ch = 0;

while (ch != 'C' && ch != 'c') {

System.out.println("Press C or c to continue.");

ch = System.in.read();

}

Listing 2–17 begins by initializing local variable ch. This variable must be initialized;

otherwise, the compiler will report an uninitialized variable when it tries to read ch’s value in the while statement’s Boolean expression.

This expression uses the conditional AND operator (&&) to test ch’s value. This operator first evaluates its left operand, which happens to be expression ch != 'C'. (The !=

operator converts 'C' from 16-bit unsigned char type to 32–bit signed int type, prior to the comparison.)

If ch does not contain C (which it does not at this point—0 was just assigned to ch), this expression evaluates to true.

The && operator next evaluates its right operand, which happens to be expression ch !=

'c'. Because this expression also evaluates to true, conditional AND returns true and while executes the compound statement.

The compound statement first outputs, via the System.out.println() method call, a message that prompts the user to press either the C key or the c key. It next reads the entered character via System.in.read() (discussed in Chapter 1), saving the character’s integer value in ch.

Following this assignment, the compound statement ends and while reevaluates its Boolean expression.

Suppose ch contains C’s integer value. Conditional AND evaluates ch != 'C', which evaluates to false. Seeing that the expression is already false, conditional AND short circuits its evaluation by not evaluating its right operand, and returns false. The while statement subsequently detects this value and terminates.

Suppose ch contains c’s integer value. Conditional AND evaluates ch != 'C', which evaluates to true. Seeing that the expression is true, conditional AND evaluates ch !=

'c', which evaluates to false. Once again, the while statement terminates.

NOTE: A for statement can be coded as a while statement. For example, for (int i = 0; i < 10; i++)

System.out.println(i);

is equivalent to int i = 0;

while (i < 10) {

System.out.println(i);

i++;

}

The do-while statement has the following syntax:

do

statement

while(Boolean expression);

This statement consists of the do reserved word, followed by a statement to repeatedly execute, followed by the while reserved word, followed by a parenthesized Boolean expression header, followed by a semicolon.

The do-while statement first executes the other statement. It then evaluates the Boolean expression. If it is true, do-while executes the other statement. Once again, the Boolean expression is evaluated. If it is still true, do-while re-executes the statement. This cyclic pattern continues.

Listing 2–18 demonstrates do-while in another example of prompting the user to enter a specific uppercase letter or its lowercase equivalent.

Listing 2–18. Prompting the user to enter a specific character via a do-while statement int ch;

do {

System.out.println("Press C or c to continue.");

ch = System.in.read();

}

while (ch != 'C' && ch != 'c');

Listing 2–18 is similar to Listing 2–17. This time, however, the compound statement is executed prior to the test. As a result, it is no longer necessary to initialize ch—ch is assigned System.in.read()’s return value prior to the Boolean expression’s evaluation.

It is sometimes useful for a loop statement to execute the empty statement repeatedly.

The actual work performed by the loop statement takes place in the statement header.

Listing 2–19 presents an example.

Listing 2–19. Reading and outputting lines of text

for (String line; (line = readLine()) != null; System.out.println(line));

Listing 2–19 uses for to present a programming idiom for copying lines of text that are read from some source, via the fictitious readLine() method in this example, to some destination, via System.out.println() in this example. Copying continues until readLine() returns null. Note the semicolon (empty statement) at the end of the line.

CAUTION: Be careful with the empty statement because it can introduce subtle bugs into your code. For example, the following code fragment is supposed to output Hello on ten lines.

Instead, only one instance of this string appears—the empty statement is executed ten times:

for (int i = 0; i < 10; i++); // this ; represents the empty statement System.out.println("Hello");

在文檔中 Java Android Development (頁 79-88)