Quantcast

P^i

Your Online Tech Magazine

Sun05192013

Last update03:26:05 AM

Back You are here: Home More Programming and Web Programming Legal Expressions for if Statements

Legal Expressions for if Statements



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

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.

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");
}
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.








blog comments powered by Disqus