Certification Objective if and switch Statements (Exam Objective 2.1)


Certification Objective —if and switch Statements (Exam Objective 2.1)

2. 1 Develop code that implements an if or switch statement; and identify legal argument types for these statements.

The if and switch statements are commonly referred to as decision statements. When you use decision statements in your program, you're asking the program to evaluate a given expression to determine which course of action to take. We'll look at the if statement first.

if-else Branching

The basic format of an if statement is as follows:

 if (booleanExpression) {   System.out.println("Inside if statement"); } 

The expression in parentheses must evaluate to (a boolean) true or false. Typically you're testing something to see if it's true, and then running a code block (one or more statements) if it is true, and (optionally) another block of code if it isn't. The following code demonstrates a legal if-else statement:

 if (x > 3) {   System.out.println("x is greater than 3"); } else {   System.out.println("x is not greater than 3"); } 

The else block is optional, so you can also use the following:

 if (x > 3) {   y = 2; } z += 8; a = y + x; 

The preceding code will assign 2 to y if the test succeeds (meaning x really is greater than 3), but the other two lines will execute regardless. Even the curly braces are optional if you have only one statement to execute within the body of the conditional block. The following code example is legal (although not recommended for readability):

 if (x > 3)     // bad practice, but seen on the exam   y = 2; z += 8; a = y + x; 

Sun considers it good practice to enclose blocks within curly braces, even if there's only one statement in the block. Be careful with code like the above, because you might think it should read as,

"If x is greater than 3, then set y to 2, z to z + 8, and a to y + x."

But the last two lines are going to execute no matter what! They aren't part of the conditional flow. You might find it even more misleading if the code were indented as follows:

 if (x > 3)   y = 2;   z += 8;   a = y + x; 

You might have a need to nest if-else statements (although, again, it's not recommended for readability, so nested if tests should be kept to a minimum). You can set up an if-else statement to test for multiple conditions. The following example uses two conditions so that if the first test fails, we want to perform a second test before deciding what to do:

 if (price < 300) {   buyProduct(); } else {   if (price < 400) {     getApproval();   }   else {     dontBuyProduct();   } } 

This brings up the other if-else construct, the if, else if, else. The preceding code could (and should) be rewritten:

 if (price < 300) {   buyProduct(); } else if (price < 400) {     getApproval () ; } else {     dontBuyProduct(); } 

There are a couple of rules for using else and else if:

  • You can have zero or one else for a given if, and it must come after any else ifs.

  • You can have zero to many else ifs for a given if and they must come before the (optional) else.

  • Once an else if succeeds, none of the remaining else ifs or elses will be tested.

The following example shows code that is horribly formatted for the real world. As you've probably guessed, it's fairly likely that you'll encounter formatting like this on the exam. In any case, the code demonstrates the use of multiple else ifs:

 int x = 1; if ( x == 3 ) { } else if (x < 4) {System.out.println("<4"); } else if (x < 2) {System.out.println("<2"); } else { System.out.println("else"); } 

It produces the output:

 <4 

(Notice that even though the second else if is true, it is never reached.) Sometimes you can have a problem figuring out which if your else should pair with, as follows:

 if (exam. done()) if (exam.getScore() < 0.61) System.out.println("Try again."); // Which if does this belong to? else System.out.println("Java master!"); 

We intentionally left out the indenting in this piece of code so it doesn't give clues as to which if statement the else belongs to. Did you figure it out? Java law decrees that an else clause belongs to the innermost if statement to which it might possibly belong (in other words, the closest preceding if that doesn't have an else). In the case of the preceding example, the else belongs to the second if statement in the listing. With proper indenting, it would look like this:

 if (exam. done())   if (exam.getScore() < 0.61)     System.out.println("Try again.");   // Which if does this belong to?   else     System.out.println("Java master!"); 

Following our coding conventions by using curly braces, it would be even easier to read:

 if (exam.done()) {   if (exam.getScore() < 0.61) {     System.out.println("Try again.");   // Which if does this belong to?   } else {     System.out.println("Java master!");   } } 

Don't get your hopes up about the exam questions being all nice and indented properly. Some exam takers even have a slogan for the way questions are presented on the exam: anything that can be made more confusing, will be.

Be prepared for questions that not only fail to indent nicely, but intentionally indent in a misleading way: Pay close attention for misdirection like the following:

 if (exam. done())   if (exam.getScore() < 0.61)     System.out.println("Try again."); else   System.out.println("Java master!"); // Hmmmmm now where does                                       // it belong? 

Of course, the preceding code is exactly the same as the previous two examples, except for the way it looks.

Legal Expressions for if Statements

The expression in an if statement must be a boolean expression. Any expression that resolves to a boolean is fine, and some of the expressions can be complex. Assume doStuff() returns true,

 int y = 5 ; int x = 2; if (((x > 3) && (y < 2)) | dostuff ()) {    System.out.println("true"); } 

which prints

 true 

You can read the preceding code as, "If both (x > 3) and (y < 2) are true, or if the result of doStuff() is true, then print true." So basically, if just doStuff() alone is true, we'll still get true. If doStuff() is false, though, then both (x > 3) and (y < 2) will have to be true in order to print true. The preceding code is even more complex if you leave off one set of parentheses as follows,

 int y = 5; int x = 2; if ((x > 3) && (y < 2) | doStuff()) {   System.out.println("true"); } 

which now prints nothing! Because the preceding code (with one less set of parentheses) evaluates as though you were saying, "If (x > 3) is true, and either (y < 2) or the result of doStuff() is true, then print true." So if (x > 3) is not true, no point in looking at the rest of the expression." Because of the short-circuit &&, the expression is evaluated as though there were parentheses around (y < 2) | doStuff(). In other words, it is evaluated as a single expression before the && and a single expression after the &&.

Remember that the only legal expression in an if test is a boolean. In some languages, 0 = = false, and 1 = = true. Not so in Java! The following code shows if statements that might look tempting, but are illegal, followed by legal substitutions:

 int trueInt = 1; int falseInt = 0; if (trueInt)             // illegal if (trueInt == true)     // illegal if (1)                   // illegal if (falseInt == false)   // illegal if (trueInt == 1)        // legal if (falseInt == 0)       // legal 

image from book
Exam Watch

One common mistake programmers make (and that can be difficult to spot), is assigning a boolean variable when you meant to test a boolean variable. Look out for code like the following:

 boolean boo = false; if (boo = true) { } 

You might think one of three things:

  1. The code compiles and runs fine, and the if test fails because boo is false.

  2. The code won't compile because you're using an assignment (=) rather than an equality test (= =).

  3. The code compiles and runs fine and the if test succeeds because boo is SET to true (rather than TESTED for true) in the if argument!

Well, number 3 is correct. Pointless, but correct. Given that the result of any assignment is the value of the variable after the assignment, the expression (boo = true) has a result of true. Hence, the if test succeeds. But the only variable that can be assigned (rather than tested against something else) is a boolean; all other assignments will result in something non-boolean, so they're not legal, as in the following:

 int x = 3; if (x = 5) { }  / Won't compile because x is not a boolean! 

Because if tests require boolean expressions, you need to be really solid on both logical operators and if test syntax and semantics.

image from book

switch Statements

A way to simulate the use of multiple if statements is with the switch statement. Take a look at the following if-else code, and notice how confusing it can be to have nested if tests, even just a few levels deep:

 int x = 3; if (x == 1) {   System.out.println("x equals 1"); } else if(x == 2) {       System.out.println("x equals 2");    }    else if(x == 3) {          System.out.println("x equals 3");       }       else {          System.out.println("No idea what x is");       } 

Now let's see the same functionality represented in a switch construct:

 int x = 3; switch (x) {    case 1:       System.out.println("x is equal to 1");       break;    case 2:       System.out.println("x is equal to 2");       break;    case 3:       System.out.println("x is equal to 3");       break;    default:       System.out.println("Still no idea what x is"); } 

Note: The reason this switch statement emulates the nested ifs listed earlier is because of the break statements that were placed inside of the switch. In general, break statements are optional, and as we will see in a few pages, their inclusion or exclusion causes huge changes in how a switch statement will execute.

Legal Expressions for switch and case

The general form of the switch statement is:

 switch (expression) {   case constant1: code block   case constant2: code block   default: code block } 

A switch's expression must evaluate to a char, byte, short, int, or, as of Java 5, an enum. That means if you're not using an enum, only variables and values that can be automatically promoted (in other words, implicitly cast) to an int are acceptable. You won't be able to compile if you use anything else, including the remaining numeric types of long, float, and double.

A case constant must evaluate to the same type as the switch expression can use, with one additional—and big—constraint: the case constant must be a compile time constant! Since the case argument has to be resolved at compile time, that means you can use only a constant or final variable that is assigned a literal value. It is not enough to be final, it must be a compile time constant. For example:

 final int a = 1; final int b; b = 2; int x = 0; switch (x) {   case a:     // ok   case b:     // compiler error 

Also, the switch can only check for equality. This means that the other relational operators such as greater than are rendered unusable in a case. The following is an example of a valid expression using a method invocation in a switch statement. Note that for this code to be legal, the method being invoked on the object reference must return a value compatible with an int.

 String s = "xyz"; switch (s.length()) {   case 1:     System.out.println("length is one");     break;   case 2:     System.out.println("length is two");     break;   case 3:     System.out.println("length is three");     break;   default:     System.out.println("no match"); } 

One other rule you might not expect involves the question, "What happens if I switch on a variable smaller than an int?" Look at the following switch:

 byte g = 2; switch(g) {   case 23:   case 128: } } 

This code won't compile. Although the switch argument is legal—a byte is implicitly cast to an int—the second case argument (128) is too large for a byte, and the compiler knows it! Attempting to compile the preceding example gives you an error something like

 Test.java:6: possible loss of precision found   : int required: byte     case 128:          ^ 

It's also illegal to have more than one case label using the same value. For example, the following block of code won't compile because it uses two cases with the same value of 80:

 int temp = 90; switch(temp) {   case 80 :  System.out.println("80");   case 80 :  System.out.println("80");   // won't compile!   case 90 :  System.out.println("90");   default :  System.out.println("default"); } 

It is legal to leverage the power of boxing in a switch expression. For instance, the following is legal:

 switch(new Integer(4)) {   case 4: System.out.println("boxing is OK"); } 

image from book
Exam Watch

Look for any violation of the rules for switch and case arguments. For example, you might find illegal examples like the following snippets:

 switch(x) {   case 0 {     y = 7;   } } switch(x) {   0: { }   1: { } } 

In the first example, the case uses a curly brace and omits the colon. The second example omits the keyword case.

image from book

Break and Fall-Through in switch Blocks

We're finally ready to discuss the break statement, and more details about flow control within a switch statement. The most important thing to remember about the flow of execution through a switch statement is this:

case constants are evaluated from the top down, and the first case constant that matches the switch's expression is the execution entry point.

In other words, once a case constant is matched, the JVM will execute the associated code block, and ALL subsequent code blocks (barring a break statement) too! The following example uses an enum in a case statement.

 enum Color {red, green, blue} class SwitchEnum {   public static void main(String [] args) {     Color c = Color.green;     switch(c) {       case red: System.out.print("red ");       case green: System.out.print("green ");       case blue: System.out.print("blue ");       default: System.out.println("done");     }   } } 

In this example case green: matched, so the JVM executed that code block and all subsequent code blocks to produce the output:

 green blue done 

Again, when the program encounters the keyword break during the execution of a switch statement, execution will immediately move out of the switch block to the next statement after the switch. If break is omitted, the program just keeps executing the remaining case blocks until either a break is found or the switch statement ends. Examine the following code:

 int x = 1; switch(x) {   case 1:  System.out.println("x is one");   case 2:  System.out.println("x is two");   case 3:  System.out.println("x is three"); } System.out.println("out of the switch"); 

The code will print the following:

 x is one x is two x is three out of the switch 

This combination occurs because the code didn't hit a break statement; execution just kept dropping down through each case until the end. This dropping down is actually called "fall-through," because of the way execution falls from one case to the next. Remember, the matching case is simply your entry point into the switch block! In other words, you must not think of it as, "Find the matching case, execute just that code, and get out." That's not how it works. If you do want that "just the matching code" behavior, you'll insert a break into each case as follows:

 int x = 1; switch(x) {   case 1: {     System.out.println("x is one");  break;   }   case 2: {     System.out.println("x is two");  break;   }   case 3: {     System.out.println("x is two");  break;   } } System.out.println("out of the switch"); 

Running the preceding code, now that we've added the break statements, will print

 x is one out of the switch 

and that's it. We entered into the switch block at case 1. Because it matched the switch() argument, we got the println statement, then hit the break and jumped to the end of the switch.

An interesting example of this fall-through logic is shown in the following code:

 int x = someNumberBetweenOneAndTen; switch (x) {   case 2:   case 4:   case 6:   case 8:   case 10: {     System.out.println("x is an even number");  break;   } } 

This switch statement will print x is an even number or nothing, depending on whether the number is between one and ten and is odd or even. For example, if x is 4, execution will begin at case 4, but then fall down through 6, 8, and 10, where it prints and then breaks. The break at case 10, by the way, is not needed; we're already at the end of the switch anyway.

Note: Because fall-through is less than intuitive, Sun recommends that you add a comment like: // fall through when you use fall-through logic.

The Default Case

What if, using the preceding code, you wanted to print "x is an odd number" if none of the cases (the even numbers) matched? You couldn't put it after the switch statement, or even as the last case in the switch, because in both of those situations it would always print x is an odd number. To get this behavior, you'll use the default keyword. (By the way, if you've wondered why there is a default keyword even though we don't use a modifier for default access control, now you'll see that the default keyword is used for a completely different purpose.) The only change we need to make is to add the default case to the preceding code:

 int x = someNumberBetweenOneAndTen; switch (x) {   case 2:   case 4:   case 6:   case 8:   case 10: {     System.out.println("x is an even number");     break;   }   default: System.out.println("x is an odd number"); } 

image from book
Exam Watch

The default case doesn't have to come at the end of the switch. Look for it in strange places such as the following:

 int x = 2; switch (x) {   case 2:  System.out.println("2");   default: System.out.println("default");   case 3: System.out.println("3");   case 4: System.out.println("4"); } 

image from book

image from book
Exam Watch

Running the preceding code prints

 2 default 3 4 

And if we modify it so that the only match is the default case:

 int x = 7; switch (x) {   case 2:  System.out.println("2");   default: System.out.println("default");   case 3: System.out.println("3");   case 4: System.out.println("4"); } 

Running the preceding code prints

 default 3 4 

The rule to remember is that default works just like any other case for fall-through!

image from book

Exercise 5-1: Creating a switch-case Statement

image from book

Try creating a switch statement using a char value as the case. Include a default behavior if none of the char values match.

  • Make sure a char variable is declared before the switch statement.

  • Each case statement should be followed by a break.

  • The default case can be located at the end, middle, or top.

image from book




SCJP Sun Certified Programmer for Java 5 Study Guide Exam 310-055
SCJP Sun Certified Programmer for Java 5 Study Guide (Exam 310-055) (Certification Press)
ISBN: 0072253606
EAN: 2147483647
Year: 2006
Pages: 131

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net