Navigation
Java Full Course: Mastering the Language Decision Making and Branching
Decision Making and Branching
1. Introduction to Decision Making and Branching
A program is rarely a simple linear sequence of instructions. Most real-world applications need to evaluate conditions and choose different paths of execution based on the outcome—whether it’s validating user input, handling different business rules, or responding to runtime events. This ability to alter the flow of control is known as decision making and branching.
In Java, decision-making constructs allow a program to select one among several alternative blocks of code to execute. The choice is typically based on the evaluation of a boolean expression (e.g., a comparison, a logical condition, or a method that returns a boolean). Once the decision is made, the program "branches" to the appropriate section of code, optionally skipping other sections.
Java provides several statements to implement decision making:
- if statement – executes a block of code if a condition is true.
- if-else statement – chooses between two blocks based on a condition.
- else-if ladder – selects one block from multiple possibilities.
- switch statement – selects among several branches based on the value of an expression.
- Nested control structures – embedding one decision construct inside another.
- Ternary operator (already covered) – a compact way to embed a simple conditional expression.
Each of these constructs gives you the power to build logic that responds intelligently to data and user interactions. Understanding when to use if-else versus switch, how to structure complex conditions, and how to avoid common pitfalls like dangling else or fall through in switch is essential for writing clear, maintainable code.
2. The if Statement
The if statement is the most fundamental decision-making construct in Java. It allows a program to execute a block of code only when a specified condition evaluates to true. If the condition is false, the block is skipped, and execution continues with the next statement after the if.
2.1 Syntax
- condition – a boolean expression (e.g.,
x > 5,isValid == true, or simply a boolean variable). - The block is a sequence of statements enclosed in curly braces
{}. If only one statement is to be executed, the braces are optional, but it is a good practice to always use them.
2.2 Simple Example
Output:
If age were 16, the message inside the if would not be printed; only the second line would appear.
2.3 Flow of Control
2.4 Using Blocks – Curly Braces
- Always use braces
{}even for a single statement. It improves readability and prevents errors when adding more statements later.
Without braces (works but risky):
With braces (safe):
2.5 Nested if Statements
An if statement can contain another if inside its block. This is called nesting.
The inner if is evaluated only when the outer condition is true.
2.6 Common Pitfalls
a) Using = instead of ==
The condition must be a boolean expression. Using = where == is intended often results in a compilation error unless the left side is a boolean variable.
b) Missing Braces Leading to Logic Errors
The second statement is not part of the if block. Use braces to avoid such bugs.
c) Dangling else
Not an issue in Java because else always associates with the nearest preceding if that doesn’t already have an else. Use braces to clarify intent.
d) Null Checks
When dealing with objects, always check for null before accessing methods or fields to avoid NullPointerException.
2.7 Best Practices
- Always use braces
{}even for single statements. This makes the code more maintainable and less error prone. - Keep conditions simple. Complex boolean expressions can be assigned to a well named variable first.
- Use positive conditions where possible (e.g.,
if (isValid)rather thanif (!isValid)). - Avoid deep nesting. If you need more than two or three levels, consider refactoring with methods or using other control structures.
- Indent consistently to make the structure clear.
2.8 The if Statement Without Braces (Valid but Discouraged)
Java allows omitting braces when exactly one statement follows the if. This is a holdover from C/C++ but is generally discouraged because it can lead to subtle bugs.
When you later add another statement, forgetting to add braces will cause it to always execute.
2.9 if with Compound Conditions
The condition can be any boolean expression, including combinations with logical operators (&&, ||, !).
Short circuit evaluation (&& and ||) ensures that the second operand is evaluated only when necessary.
2.10 Examples
Example 1: Simple comparison
Example 2: Using a boolean variable
Example 3: Guarding against division by zero
Example 4: Checking string content (with null check)
2.11 Key Points to Remember
- The
ifstatement executes its block only if the condition is true. - The condition must be a boolean expression.
- Always use braces
{}to define the block, even for a single statement. - Nested
ifstatements are allowed, but keep nesting shallow. - Avoid the common mistake of using
=instead of==for comparison. - Use short circuit operators to protect against null and expensive computations.
- Keep conditions readable by extracting complex logic into named variables.
3. The if-else Statement
The if-else statement extends the basic if statement by providing an alternative block of code that executes when the condition is false. This allows a program to choose between two mutually exclusive paths.
3.1 Syntax
- The
elseblock is optional but must immediately follow theifblock (or another else-if). - Each block can contain zero or more statements. Braces are recommended even for single statements.
3.2 Simple Example
Output: You are not yet eligible to vote.
3.3 Flow of Control
Exactly one of the two blocks is executed; control then passes to the next statement after the if-else.
3.4 Nested if-else Statements
You can place if or if-else inside another if or else block.
3.5 Dangling else Ambiguity
In Java, an else always associates with the nearest preceding if that does not already have an else. This is resolved by the compiler without ambiguity. However, proper indentation and braces make the intent clear.
Example without braces (risky):
The else belongs to the inner if, not the outer one. Always use braces to avoid confusion.
3.6 Multiple Statements in Blocks
Each block can contain any number of statements, including declarations (but variable scope is limited to the block).
Variables declared inside a block are not accessible outside it.
3.7 Common Pitfalls
a) Misplaced Semicolon
b) Using = Instead of ==
c) Unintended else Attachment
Without braces, the else may attach to the wrong if. Always use braces for clarity.
3.8 Best Practices
- Always use braces
{}for bothifandelseblocks. - Keep the logic simple.
- Avoid deep nesting.
- Order conditions logically.
- Use meaningful variable names.
3.9 Using if-else with Boolean Variables
When the condition is already a boolean, you can write:
Avoid redundant comparisons like if (isValid == true).
3.10 The Ternary Operator as an Alternative
For simple assignments, the ternary operator ? : can replace an if-else:
3.11 Examples
Example 1: Determining if a number is positive, negative, or zero (with nesting)
Example 2: Checking leap year
Example 3: Guarding against null
3.12 Key Points to Remember
- The
if-elsestatement executes one of two blocks based on a boolean condition. - Exactly one block (the
ifblock or theelseblock) is executed. - Braces are optional for single statements but highly recommended.
- An
elsealways attaches to the nearest precedingif. - Variables declared inside a block are local to that block.
4. The else-if Ladder
The else-if ladder (multi-way branching) is used when a program must choose among several mutually exclusive alternatives.
4.1 Syntax
- The chain can have any number of
else ifblocks. - The final
elseis optional but recommended. - Once a condition is found to be true, the rest of the ladder is skipped.
4.2 Flow of Control
Only the first matching block (or the final else block) is executed; control then exits the entire ladder.
4.3 Simple Example
4.4 Characteristics
- Mutual Exclusion: Only one block can execute.
- Order Matters: The first true condition wins. Arranging from most specific to most general is crucial.
4.5 Comparison with Nested if-else
An else-if ladder is essentially a flattened version of nested if-else, making it more readable and avoiding excessive indentation.
4.6 Common Pitfalls
- Overlapping Conditions: Ensure conditions are mutually exclusive when that is the intent.
- Redundant Conditions: Simplify conditions that are already covered by previous ones.
- Forgetting Braces: Always use braces to define the blocks.
4.7 Best Practices
- Order conditions from most specific to most general.
- Limit the number of branches (consider
switchor polymorphism for many branches). - Always include a final
elseto catch unexpected values. - Keep the blocks short; extract to methods if they become complex.
4.8 Examples
Example: Categorizing age groups
Example: Commission calculation
4.9 else-if vs. switch
Use else-if for conditions involving ranges or complex boolean logic. Use switch when comparing one variable against discrete equality checks.
4.10 Key Points to Remember
- The
else-ifladder tests multiple conditions in sequence. - The first true condition executes its block, and the rest are skipped.
- Order matters: evaluate top to bottom.
- Use braces
{}to avoid logic errors.
5. The switch Statement
The switch statement is a multi-way branching construct that allows a variable or expression to be tested for equality against a list of values (called cases). It provides a cleaner and often more efficient alternative to long else-if ladders when the decision is based on a single discrete value.
5.1 Traditional switch Syntax (Pre Java 12)
- expression – must evaluate to a
byte,short,char,int,String(Java 7+), or anenum. - case value – a constant expression (compile-time constant) of a type compatible with the expression.
- break – exits the switch block; without it, execution "falls through" to the next case.
- default – optional; executes if no case matches. Can appear anywhere, but conventionally at the end.
5.2 Enhanced switch (Java 12–14)
Java 12 introduced preview features that became standard in Java 14: arrow syntax (->) and yield for returning values.
a) Arrow Syntax (->) – No Fall-Through
- No
breakneeded; only the matched case executes. - On the right side, you can use a single expression or a block
{ ... }. - Multiple constants per case are allowed:
case value1, value2 -> ....
b) switch as an Expression (using yield)
Starting with Java 14, switch can be used as an expression that returns a value.
- Every branch must produce a value, and the types must be compatible.
yieldis used to return a value from a block.
5.3 Fall-Through in Traditional switch
If you omit break, execution continues into the next case. This is called "fall-through".
Fall-through can be useful when multiple cases share the same logic:
5.4 Supported Types in switch
| Type | Supported Since |
|---|---|
byte | Java 1.0 |
short | Java 1.0 |
char | Java 1.0 |
int | Java 1.0 |
enum | Java 5 |
String | Java 7 |
Wrappers (Byte, Short, Character, Integer) | Java 1.0 (auto-unboxing works) |
boolean, long, float, double | Not allowed directly |
5.5 Case Labels
- Must be compile-time constants (literals,
finalvariables initialized with constants, enum constants). - Cannot be
nullfor String cases. - Cannot be duplicate values.
5.6 switch with Strings
The String comparison is case-sensitive and uses equals() internally.
5.7 switch with Enums
When using enums, you don't need to qualify the constants with the enum name inside the switch.
5.8 Using yield in Switch Expressions (Java 14+)
Switch expressions must cover all possible values or include a default. The yield keyword returns a value from a block.
5.9 Common Pitfalls
a) Missing break (Unintended Fall-Through)
If x == 1, both lines print. This is often a bug. Use the enhanced syntax or add break deliberately.
b) Not Handling All Cases
If you omit default and none of the cases match, the switch does nothing. It's a good practice to include a default for unexpected values.
c) Using Non-Constant Expressions in case
d) Using Unsupported Types
e) Duplicate Cases
f) Using null in switch with String or Enum
Always check for null before switching on a reference type.
5.10 switch vs. if-else
| Feature | switch | if-else Ladder |
|---|---|---|
| Condition | Single expression with discrete equality | Arbitrary boolean expressions |
| Use case | Multiple fixed values, ranges via fall-through | Ranges, complex logic, boolean conditions |
| Readability | Clean for many discrete values | Can become verbose for many values |
| Performance | Can be optimized (jump table) for integral types | Linear evaluation of conditions |
| Type support | Limited to integral, String, enum | Any boolean expression |
| Fall-through | Possible (traditional syntax) | Not applicable |
Use switch when you have one variable being compared to many constant values. Use if-else for ranges, conditions involving multiple variables, or non-equality checks.
5.11 Best Practices
- Prefer enhanced switch (
->) in Java 14+ to avoid accidental fall-through and to make code more concise. - Always include a
defaultbranch unless you are absolutely sure all possible values are covered (e.g., with enums, consider addingdefaultto handle future enum constants). - Use
yieldfor switch expressions when you need to return a value. - Check for
nullbefore switching onStringorenumto avoidNullPointerException. - Keep case blocks short; if a case requires many lines, extract into a method.
- Use
switchoverif-elsewhen you have 3 or more discrete cases for better readability.
5.12 Examples
Example 1: Traditional with fall-through for shared logic
Example 2: Enhanced switch with arrow and multiple constants
Example 3: Switch expression with yield and block
Example 4: Using enum in enhanced switch
5.13 Key Points to Remember
switchtests a single expression against multiple constant values.- Traditional
switchrequiresbreakto prevent fall-through; enhancedswitchuses->which does not fall through. - Supported types:
byte,short,char,int,String,enum, and their wrappers. switchcan be used as a statement (no return) or as an expression (returns a value) in Java 14+.defaultis optional but recommended.- Case labels must be compile-time constants and cannot be
null. - Always handle
nullseparately when switching onStringorenum. - For complex conditions or ranges, prefer
if-else.
