Chapter 4 Making Decisions Notes Flashcards
STATEMENTS AND BLOCKS
a Java statement is a complete unit of execution in Java, terminated with a semicolon (;).
// Single statement patrons++;
a block of code in Java is a group of zero or more statements between balanced braces ({}) and can be used anywhere a single statement is allowed.
// Statement inside a block { patrons++; }
The structure of an if statement
if (booleanExpression) { // Branch if true }
- if keyword
- Parentheses (required)
- Curly braces required for block of multiple statements, optional for single statement
!NOTES: VERIFYING THAT THE IF STATEMENT EVALUATES TO A BOOLEAN EXPRESSION
WATCH INDENTATION AND BRACES
In Java tabs are just whitespace and are not evaluated as part of the execution. When you see a control flow statement in a question, be sure to trace the open and close braces of the block, ignoring any indentation you may come across.
if(hourOfDay < 11) System.out.println("Good Morning"); morningGreetingCount++; // will always execute the increment operation.
The structure of an else statement
if (booleanExpression) { // Branch if true } else { // Branch if false }
- if keyword
- Parentheses (required)
- Curly braces required for block of multiple statements, optional for single statement
- Optional else statement
else if statement
else if statement
if(hourOfDay < 11) { System.out.println("Good Morning"); } else if(hourOfDay < 15) { System.out.println("Good Afternoon"); } else { System.out.println("Good Evening"); }
Unreachable statement
if(hourOfDay < 15) { System.out.println("Good Afternoon"); } else if(hourOfDay < 11) { System.out.println("Good Morning"); // COMPILES BUT IS UNREACHABLE } else { System.out.println("Good Evening"); }
The structure of a switch statement
switch (variableToTest) { case constantExpression1: // Branch for case1; break; case constantExpression2: // Branch for case2; break; ... default: // Branch for default; }
- switch keyword required
- Parentheses (required)
- Beginning curly brace (required)
- switch statement may contain 0 or more case branches
- Optional break
- Optional default that may appear anywhere within switch statement
- Ending curly brace (required)
Proper Switch Syntax
int month = 5; switch month { // DOES NOT COMPILE case 1: System.out.print("January"); } switch (month) // DOES NOT COMPILE case 1: System.out.print("January"); switch (month) { case 1: 2: System.out.print("January"); // DOES NOT COMPILE } switch (month) { case 1 || 2: System.out.print("January"); // DOES NOT COMPILE }
- The first switch statement does not compile because it is missing parenthesesaround the switch variable.
- The second statement does not compile because it is missing braces around the switch body.
- The third statement does not compile because the case keyword is missing before the 2: label.
- Each case statement requires the keyword case, followed by a value and a colon (:).
- Finally, the last switch statement does not compile because 1 || 2 uses the short-circuit boolean operator, which cannot be applied to numeric values. A single bitwise operator (|) would have allowed the code to compile, although the interpretation of this might not be what you expect. It would then only match a value of month that is the bitwise result of 1 | 2, which is 3, and would not match month having a value 1 or 2. You don’t need to know bitwise arithmetic for the exam, but you do need to know proper syntax for case statements.
Valid?
switch (month) {}
Valid
Data types supported by switch statements:
- int and Integer
- byte and Byte
- short and Short
- char and Character
- String
- enum values
- var (if the type resolves to one of the preceding types)
Java 12 launched with a Preview release of a powerful new feature called Switch Expressions, a construct that combines switch statements with lambda expressions and allows switch statements to return a value.
Switch Control Flow
The exam creators are fond of switch examples that are missing break statements! When evaluating switch statements on the exam, always consider that multiple branches may be visited in a single execution.
Acceptable Case Values
First off, the values in each case statement must be compile-time constant values of the same data type as the switch value.
This means you can use only literals, enum constants, or final constant variables of the same data type.
By final constant, we mean that the variable must be marked with the final modifier and initialized with a literal value in the same expression in which it is declared.
final int getCookies() { return 4; } void feedAnimals() { final int bananas = 1; int apples = 2; int numberOfAnimals = 3; final int cookies = getCookies(); switch (numberOfAnimals) { case bananas: case apples: // DOES NOT COMPILES case getCookies(): // DOES NOT COMPILE case cookies : // DOES NOT COMPILE case 3 * 5 : } }
- The bananas variable is marked final, and its value is known at compile-time, so it is valid.
- The apples variable is not marked final, even though its value is known, so it is not permitted.
- The next two case statements, with values getCookies() and cookies, do not compile because methods are not evaluated until runtime, so they cannot be used as the value of a case statement, even if one of the values is stored in a final variable.
- The last case statement, with value 3 * 5, does compile, as expressions are allowed as case values, provided the value can be resolved at compile-time. They also must be able to fit in the switch data type without an explicit cast. We’ll go into that in more detail shortly.
- Next, the data type for case statements must all match the data type of the switch variable. For example, you can’t have a case statement of type String, if the switch statement variable is of type int, since the types are incomparable.
private int getSortOrder(String firstName, final String lastName) { String middleName = "Patricia"; final String suffix = "JR"; int id = 0; switch(firstName) { case "Test": return 52; case middleName: // DOES NOT COMPILE id = 5; break; case suffix: id = 0; break; case lastName: // DOES NOT COMPILE id = 8; break; case 5: // DOES NOT COMPILE id = 7; break; case 'J': // DOES NOT COMPILE id = 10; break; case java.time.DayOfWeek.SUNDAY: // DOES NOT COMPILE id=15; break; } return id; }
- The first case statement, “Test”, compiles without issue since it is a String literal and is a good example of how a return statement, like a break statement, can be used to exit the switch statement early.
- The second case statement does not compile because middleName is not a constant value, despite having a known value at this particular line of execution. If a final modifier was added to the declaration of middleName, this case statement would have compiled.
- The third case statement compiles without issue because suffix is a final constant variable.
- In the fourth case statement, despite lastName being final, it is not constant as it is passed to the function; therefore, this line does not compile as well.
- Finally, the last three case statements do not compile because none of them has a matching type of String, the last one being an enum value.
Numeric Promotion and Casting
short size = 4; final int small = 15; final int big = 1_000_000; switch(size) { case small: case 1+2 : case big: // DOES NOT COMPILE }
- the compiler can easily cast small from int to short at compile-time because the value 15 is small enough to fit inside a short. This would not be permitted if small was not a compile-time constant. Likewise, it can convert the expression 1+2 from int to short at compile-time.
- On the other hand, 1_000_000 is too large to fit inside of short without an explicit cast, so the last case statement does not compile.