L6: Decision-making Statements in Java

Overview

  • Decision-making statements allow a program to follow different paths based on specific conditions, enhancing the logic and functionality of your code.
  • Before decision-making, code execution was sequential. Now, you can introduce multiple execution paths.

The if Statement

  • The if statement evaluates a boolean condition:

    if (condition) {
        // Statement(s) to execute if condition is true
    }
  • If the condition is true, the statements inside the braces execute. If false, they are skipped.

  • Relational operators (<><=>=) and equality operators (==!=) are commonly used within if conditions.

  • Example:

    int age = 18;
    if (age >= 18) {
        System.out.println("You are an adult.");
    }

The if-else Statement

  • Extends the if statement to provide an alternative path if the condition is false:

    if (condition) {
        // Statement(s) if condition is true
    } else {
        // Statement(s) if condition is false
    }
  • Only one of the blocks (if or else) will execute.

  • Example:

    int score = 75;
    if (score >= 50) {
        System.out.println("Pass");
    } else {
        System.out.println("Fail");
    }

Multi-way Branching with else if

  • Allows for multiple conditions to be checked sequentially:

    if (condition1) {
        // Statement(s) if condition1 is true
    } else if (condition2) {
        // Statement(s) if condition2 is true
    } else {
        // Statement(s) if none of the above conditions are true
    }
  • Conditions are evaluated one by one until a true condition is found, at which point the corresponding block executes.

  • Example:

    int number = 0;
    if (number > 0) {
        System.out.println("Positive");
    } else if (number < 0) {
        System.out.println("Negative");
    } else {
        System.out.println("Zero");
    }

The switch Statement

In Java, you can’t directly use complex expressions in a traditional switch-case statement. The case labels must be constant expressions.

  • Used for multi-way branching based on the value of an expression:

    switch (expression) {
        case value1:
            // Statement(s)
            break;
        case value2:
            // Statement(s)
            break;
        default:
            // Statement(s)
    }
  • Each case matches a potential value of the expression. The default block runs if no cases match.

  • The break statement prevents “fall-through” to subsequent cases. Without it, execution continues through the remaining cases.

  • Example:

    char grade = 'B';
    switch (grade) {
        case 'A':
            System.out.println("Excellent");
            break;
        case 'B':
            System.out.println("Good");
            break;
        default:
            System.out.println("Invalid grade");
    }

The Conditional (Ternary) Operator

  • A compact way to perform simple if-else operations:

    variable = (condition) ? expression1 : expression2;
  • If the condition is trueexpression1 is evaluated; otherwise, expression2 is evaluated.

  • Example:

    int age = 20;
    String result = (age >= 18) ? "Adult" : "Minor";

Logical Operators

  • AND (&&): True if both operands are true.

  • OR (||): True if at least one operand is true.

  • NOT (!): Reverses the truth value.

  • Used to create complex conditions:

    if (age > 18 && age < 65) {
        System.out.println("Working-age adult");
    }

Short-circuit Evaluation

  • For &&: If the first operand is false, the second operand is not evaluated since the overall expression is already false.
  • For ||: If the first operand is true, the second operand is not evaluated since the overall expression is already true.
  • Useful for optimizing code and avoiding unnecessary computation.

Comparing Strings

  1. equals() Method:

    • Compares the content of two strings, not their memory references.

    • Example:

      String str1 = "hello";
      String str2 = new String("hello");
      if (str1.equals(str2)) {
          System.out.println("Strings are equal.");
      }
  2. String Interning and String Constant Pool:

    • Literal strings are stored in a common pool to optimize memory usage.
    • Directly assigning strings (e.g., String str = "text";) uses the pool, whereas using new (e.g., new String("text");) creates a separate object in the heap.
  3. compareTo() Method:

    • Compares two strings lexicographically (dictionary order) based on Unicode values.

    • Returns:

      • 0 if strings are equal.
      • A negative value if the calling string is less than the argument.
      • A positive value if the calling string is greater than the argument.
    • Example:

      String a = "apple";
      String b = "banana";
      int result = a.compareTo(b);  // Returns a negative number since "apple" < "banana"

Tracing if and switch Statements

  • Tracing: Refers to following the flow of execution in code to understand which statements are executed based on various conditions.
  • For if statements, trace the conditions in the order they appear.
  • For switch statements, trace the case values matched and follow the execution until a break or the end of the statement.

Additional Concepts

  • Nesting: Placing one if or if-else statement inside another. Use careful indentation to make the code readable.
  • Dangling else Problem: In nested if statements, else pairs with the nearest unmatched if. Use braces {} to clarify associations.