Conditional Statements
Table of Contents
Introduction
Think about the last time you went to a grocery store. If it's anything like my local supermarket, when you approach the sliding doors to enter they appear to open as if they were operated by invisible elves. If we're able to reasonably convince ourselves that it isn't magical elves, there must be something present allowing for that movement to occur. Further investigation would have us finding a sensor which is able to detect whether some body is in front of the door and if that's the case the mechanism to open the door should fire. Furthermore, there is something preventing the door from opening if there is nothing detectable. The internal logic of the automatic door is conditional on the state of its components.
Programs too will have special logic that will only be used in the event a certain condition is met. In Java, these logical scaffolds are called conditional statements.
Control Flow
Conditional statements are used to direct the runtime behavior of the executing program. Depending on how they are evaluated, conditional statements will decide which set of instructions are processed next. In computer science we call this the control flow of a program—i.e. how each instruction flows into the next. Java provides a few different statements to aid in the construction of a program's control flow.
if Statement
The if statement is the fundamental conditional statement. It's syntax is as follows:
1: if(conditional) 2: statement; //Do this
As long as conditional evaluates to a true value then the statement will be executed. A filled in example should illustrate the point:
1: public class If{ 2: static final int X = _; // Will set later... 3: public static void main(String[] args){ 4: System.out.println("Welcome to the even checker!"); 5: if(X % 2 == 0) 6: System.out.printf("%d is even!%n", X); 7: } 8: }
If I compile and run this with X set to 4, I get the following results:
josephraskind@stargazer:/tmp/cond$ javac If.java; java If Welcome to the even checker! 4 is even!
What about if I set X equal to 5?
josephraskind@stargazer:/tmp/cond$ javac If.java; java If Welcome to the even checker!
What happened to my printout? Well, since the conditional failed the corresponding call to System.out.printf was not executed. The printf statement is attached to the if statement evaluating a true conditional—it will never execute if a false is evaluated.
Taking a look at the bytecode generated by javap -c If.class should help us understand what's happening:
1: public class If { 2: static int X; 3: 4: public If(); 5: Code: 6: 0: aload_0 7: 1: invokespecial #1 // Method java/lang/Object."<init>":()V 8: 4: return 9: 10: public static void main(java.lang.String[]); 11: Code: 12: 0: getstatic #7 // Field java/lang/System.out:Ljava/io/PrintStream; 13: 3: ldc #13 // String Welcome to the even checker! 14: 5: invokevirtual #15 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 15: 8: getstatic #21 // Field X:I 16: 11: iconst_2 17: 12: irem 18: 13: ifne 38 19: 16: getstatic #7 // Field java/lang/System.out:Ljava/io/PrintStream; 20: 19: ldc #27 // String %d is even!%n 21: 21: iconst_1 22: 22: anewarray #2 // class java/lang/Object 23: 25: dup 24: 26: iconst_0 25: 27: getstatic #21 // Field X:I 26: 30: invokestatic #29 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer; 27: 33: aastore 28: 34: invokevirtual #35 // Method java/io/PrintStream.printf:(Ljava/lang/String;[Ljava/lang/Object;)Ljava/io/PrintStream; 29: 37: pop 30: 38: return 31: 32: static {}; 33: Code: 34: 0: iconst_5 35: 1: putstatic #21 // Field X:I 36: 4: return 37: }
There's a lot going on here. First, #13 and #27 represent the locations in the constant pool for the two string constants used in the print statements. Line 13 loads the "Welcome..." string into the first argument, and Line 14 calls System.out.println. Lines 15-17 represent the conditional expression x % 2 == 0: 4 is loaded into the operator stack alongside the constant 2 and the integer remainder operator is called. Line 18 represents the conditional check which is seeing if the remainder is not equal to 0. If the remainder does not equal to 0 then control will be redirected over to Line 30 or instruction 38:, otherwise every further instruction will be processed. Therefore when X is equal to 5 control will be transferred ober to 38: and the second call to printf will be passed over.
if statements can also encompass more than one statement. For example:
1: if(conditional){ // Start block with { 2: statement 1; 3: statement 2; 4: .... 5: statement N; 6: } // End block with }
Applied to a "real code" expmaple we would see:
1: public class If{ 2: static final int X = _; // Will set later... 3: public static void main(String[] args){ 4: System.out.println("Welcome to the even checker!"); 5: if(X % 2 == 0){ 6: System.out.printf("%d is even!%n", X); 7: System.out.printf("Isn't that neat!\n"); 8: } 9: } 10: }
Running the above with X equal to 10 we get:
josephraskind@stargazer:/tmp/cond$ javac If.java; java If Welcome to the even checker! 10 is even! Isn't that neat!
And with X equal to 13:
josephraskind@stargazer:/tmp/cond$ javac If.java; java If Welcome to the even checker!
Be careful when omitting "{}" from your conditional statements! Without them, Java will only match the first statement to the conditional's control flow behaviour. It's good practice to ere on the side of caution and always include brackets when possible.
else if
if statements can be further modified to allow for mutually exclusive behaviors. For example, say we didn't want users to enter negative numbers we could write:
1: public class Ifs{ 2: static final int X = -4; // Will set later... 3: public static void main(String[] args){ 4: System.out.printf("Welcome to the even checker!\n"); 5: if(X < 0){ 6: System.out.printf("Ew! %d is negative!\n", X); 7: } 8: if(X % 2 == 0){ 9: System.out.printf("%d is even!\n", X); 10: } 11: if(X % 2 != 0){ 12: System.out.printf("%d is odd!\n", X); 13: } 14: } 15: }
But if I run the above code with X equal to -4 I get the following results:
josephraskind@stargazer:/tmp/cond$ javac Ifs.java; java Ifs Welcome to the even checker! Ew! -4 is negative! -4 is even!
But this wasn't what I wanted! I didn't want to print out the evenness of the negative number!
We can solve this with the use of an else if clause:
1: public class Ifs{ 2: static final int X = _; // Will set later... 3: public static void main(String[] args){ 4: System.out.printf("Welcome to the even checker!\n"); 5: if(X < 0){ 6: System.out.printf("Ew! %d is negative!\n", X); 7: }else if(X % 2 == 0){ 8: System.out.printf("%d is even!\n", X); 9: }else if(X % 2 != 0){ 10: System.out.printf("%d is odd!\n", X); 11: } 12: } 13: }
Now if I run the above code with X equal to -4 we'll see something different:
josephraskind@stargazer:/tmp/cond$ javac Ifs.java; java Ifs Welcome to the even checker! Ew! -4 is negative!
The if else clause makes each subsequent if block mututally exclusive. No two blocks can be entered for the same set of conditional checks.
else
Sometimes we want mutually exclusive behaviors without having to write an additional conditional check. For example,
1: public class Else{ 2: final static int X = 4; // Will set later... 3: public static void main(String[] args){ 4: System.out.printf("Welcome to the even checker!\n"); 5: if(X % 2 == 0){ 6: System.out.printf("%d is even!\n", X); 7: } 8: if(X % 2 != 0){ 9: System.out.printf("%d is odd!\n", X); 10: } 11: } 12: }
gets the job done, but it looks a bit clunky. There's a lot more work our eyes have to do when scanning the code. Instead we can write,
1: public class Else{ 2: final static int X = 4; // Will set later... 3: public static void main(String[] args){ 4: System.out.printf("Welcome to the even checker!\n"); 5: if(X % 2 == 0){ 6: System.out.printf("%d is even!\n", X); 7: }else{ 8: System.out.printf("%d is odd!\n", X); 9: } 10: } 11: }
now X % 2 != 0 is implied as it is the only other possibility if the original conditional check fails.
We can combine this with our negative check above (Listing 12):
1: public class Ifs{ 2: static final int X = -4; // Will set later... 3: public static void main(String[] args){ 4: System.out.printf("Welcome to the even checker!\n"); 5: if(X < 0){ 6: System.out.printf("Ew! %d is negative!\n", X); 7: }else if(X % 2 == 0){ 8: System.out.printf("%d is even!\n", X); 9: }else(X % 2 != 0){ 10: System.out.printf("%d is odd!\n", X); 11: } 12: } 13: }
You can only ever have one else in your if statement conditional chain.
switch Statement
The switch statement is a variation of the if statement. It provides slightly different functionality to using if-else statement chains. The syntax is as follows:
1: switch(expr){ 2: case SOMETHING: 3: statement 1; // Do statement 4: case SOMETHING_ELSE: 5: statement 2; // Do statement 6: break; // Exit control flow 7: default: 8: statement 3; // Do statement 9: }
The switch statement takes an expression that resolves to an integral type, a String type, or an Enum type. And will transfer control to the block of code underneath the corresponding label. The default label is used when no corresponding label for the expression's value can be found. The break statement transfers control out of the switch block—this is particularly useful because without it the control will "fall through" to the next case. Meaning in the above example if expr resolves to SOMETHING then both statement 1 and statement 2 will be executed (statement 3 will not because of the break statement).
?: Operator
Although not strictly a conditional statement, the ?: "ternary" operator is often bunched into the same group due to its conditional evaluation logic. The syntax is as follows
conditional ? eval_true : eval_false
Using the evenness example from earlier:
1: public class Ternary{ 2: final static int X = _; 3: public static void main(String[] args){ 4: System.out.printf("Welcome to the even checker!\n"); 5: System.out.printf(X % 2 == 0 ? "%d is even!\n" : "%d is odd!\n" , X); 6: } 7: }
Compiling and running the above gives us:
josephraskind@stargazer:/tmp/cond$ javac Ternary.java; java Ternary Welcome to the even checker! 4 is even!
Exercises
- Write a Java program using an
ifstatement that checks if afinal int Xis greater than 100 and prints "X is large!" if so. Test it with at least three different values. What happens when the condition is false? - Modify Listing 2 to also print "X is not even!" when
Xis odd using anelseclause. Test with both even and odd values. Why is this preferable to writing a secondifstatement with the conditionX % 2 != 0? - Write a Java program that uses
if,else if, andelseto classify afinal int Xinto one of the following categories and prints the result:- Negative
- Zero
- Between 1 and 100 inclusive
- Greater than 100
- The lecture warns that omitting
{}from anifstatement only attaches the first statement to the conditional. Write a Java program that demonstrates this bug by writing anifwithout braces followed by twoSystem.out.printlncalls. Which call is controlled by theif? Verify by testing with a condition that evaluates to false. - Write a Java program using a
switchstatement that takes afinal int daybetween 1 and 7 and prints the corresponding day of the week. Use adefaultcase for any value outside that range. - The lecture states that without a
breakstatement, control "falls through" to the next case in aswitch. Write a Java program that demonstrates this by writing aswitchwith three cases and nobreakstatements. What gets printed when the first case matches? When might fall-through behavior actually be useful? Rewrite the following
if-elsechain as aswitchstatement:1: final int X = 2; 2: if(X == 1) System.out.println("one"); 3: else if(X == 2) System.out.println("two"); 4: else if(X == 3) System.out.println("three"); 5: else System.out.println("other");
Are there any cases where a
switchcannot replace anif-elsechain? Note that unlike C, Java'sswitchalso acceptsStringandenumtypes.- Write a Java program that uses nested
ifstatements to check whether afinal int Xis both positive and even. Print an appropriate message for each of the four possible combinations: positive even, positive odd, negative even, negative odd. - The bytecode output in Listing 5 shows that the JVM uses an
ifne(jump if not equal to zero) instruction to implement theifstatement. Looking at the bytecode, identify which line performs the conditional jump and where control is transferred when the condition is false. How does this compare to what you would expect from the high-level Java source? - Further modify the ternary example in Listing 19 to include a check for a negative number all in the same line.