Study guide

2.1 Conditional Branching with if/else and the Ternary Operator

Oracle Java SE 17 Developer Certified Professional 1Z0-829

Track your progress as you read

Finished sections get a check mark.

1 Introduction: The 1Z0-829 Exam

About the Java SE 17 Developer (1Z0-829) Exam

2 Chapter 1: Java Fundamentals & Language Basics

1.1 Primitive Types, Literals, Wrapper Classes, and Type Promotion/Casting 1.2 Local Variable Type Inference (`var`) Rules and Scoping 1.3 Operators, Precedence, Evaluation Order, and Short-Circuit Evaluation 1.4 Text Blocks, String Immutability, and StringBuilder APIs

3 Chapter 2: Program Flow & Decision Constructs

2.1 Conditional Branching with if/else and the Ternary Operator 2.2 Switch Statements and Switch Expressions 2.3 Iteration Constructs, Loop Control, and Branching Labels

4 Chapter 3: Object-Oriented Design & Class Mechanics

3.1 Class Declarations, Field/Method Signatures, and Access Modifiers 3.2 Constructors, Overloading, Initialization Order, and Garbage Collection 3.3 Inheritance, Method Overriding, Polymorphism, and `super`/`this` 3.4 Abstract Classes, Static Members, and Object Methods (`equals`, `hashCode`, `toString`)

5 Chapter 4: Advanced OOP: Interfaces, Records & Sealed Types

4.1 Interface Architecture: Default, Static, and Private Methods 4.2 Enumerations: Constants, Constructors, Methods, and Custom Bodies 4.3 Records: Canonical/Compact Constructors, Components, and Immutability 4.4 Sealed Classes and Interfaces: `permits`, Hierarchy Constraints, and Modifiers

6 Chapter 5: Pattern Matching & Nested Types

5.1 Pattern Matching for `instanceof` and Flow Scoping Mechanics 5.2 Nested Types: Member Inner, Static Nested, Local, and Anonymous Classes 5.3 Defensive Programming, Immutability Patterns, and Validation

7 Chapter 6: Generics, Collections & Arrays

6.1 Generic Classes, Interfaces, Methods, and Type Erasure 6.2 Bounded Type Parameters and Wildcards (PECS Rule) 6.3 Collections Framework: List, Set, Queue, and Deque APIs 6.4 The Map Interface, Sorting, Comparable, and Comparator 6.5 Arrays: Declaration, Initialization, Multidimensional Arrays, and the Arrays Utility Class

8 Chapter 7: Functional Programming & Lambda Expressions

7.1 Functional Interfaces and Lambda Syntax Rules 7.2 Standard Functional Interfaces in `java.util.function` 7.3 Method References: Static, Bound, Unbound, and Constructor References

9 Chapter 8: The Stream API

8.1 Stream Lifecycle: Creation, Pipeline Architecture, and Lazy Evaluation 8.2 Intermediate Stream Operations: Filtering, Mapping, Sorting, and Slicing 8.3 Terminal Stream Operations: Reduction, Matching, Finding, and Collecting 8.4 Primitive Streams (`IntStream`, `LongStream`, `DoubleStream`) and Numeric Statistics

10 Chapter 9: Advanced Streams & Collectors

9.1 The Optional Class: Safe Null Handling, Transformation, and Chaining 9.2 The Collectors API: Downstream Reductions, Grouping, and Partitioning 9.3 Parallel Streams: Fork/Join Pool, Spliterators, and Concurrency Pitfalls

11 Chapter 10: Exception Handling

10.1 The Java Exception Hierarchy: Checked vs. Unchecked Exceptions and Errors 10.2 Exception Constructs: `try-catch-finally`, Multi-Catch, and Rethrowing 10.3 Try-With-Resources, `AutoCloseable`, Suppressed Exceptions, and Custom Exceptions

12 Chapter 11: Date/Time API & Localization

11.1 Date and Time Core Types: `LocalDate`, `LocalTime`, `LocalDateTime` 11.2 Timestamps, Intervals, and Durations: `Instant`, `Period`, and `Duration` 11.3 Time Zones, Daylight Saving Time (DST) Offsets, and `ZonedDateTime` 11.4 Internationalization and Localization: `Locale`, `ResourceBundle`, and Formatters 11.5 Formatting and Parsing Messages, Numbers, Percentages, and Localized Dates

13 Chapter 12: Java Platform Module System (JPMS)

12.1 Module Architecture, `module-info.java`, and Module Paths 12.2 Module Directives: `requires`, `requires transitive`, `exports`, and Qualified Exports 12.3 Reflection, Deep Encapsulation, `opens`, and Open Modules 12.4 Services in JPMS (`uses`, `provides...with`), Migration Paths, and Tooling (`jlink`, `jdeps`) 12.5 Compiling and Packaging Code: Non-Modular JARs, Modular JARs, and Migration Strategies

14 Chapter 13: Concurrency & Multithreading

13.1 Thread Fundamentals, `Runnable`, `Callable`, and Thread Lifecycle 13.2 Memory Visibility, `volatile`, Intrinsic Locks, and Synchronization 13.3 The Concurrency Framework: `ExecutorService`, Thread Pools, and `Future` 13.4 Concurrent Collections, Atomic Variables, Explicit Locks, and `CompletableFuture`

15 Chapter 14: Java I/O and NIO.2

14.1 Classical I/O: Byte and Character Streams, Readers, Writers, and Buffering 14.2 Object Serialization, `Serializable`, `transient`, and `serialVersionUID` 14.3 NIO.2 Architecture: `Path`, `Paths`, and Basic `Files` Operations 14.4 Advanced NIO.2: Directory Walking, Streams (`Files.lines`, `walk`), and `WatchService`

16 Chapter 15: Accessing Databases with JDBC

15.1 JDBC Architecture, Drivers, `DriverManager`, and `DataSource` Connections 15.2 SQL Execution: `Statement`, `PreparedStatement`, and `CallableStatement` 15.3 `ResultSet` Navigation, Data Types, and Transaction Management (Commit, Rollback, Savepoints)

17 Chapter 16: Annotations & the Java Logging API

16.1 Standard Annotations: @Override, @FunctionalInterface, @Deprecated, @SuppressWarnings, and @SafeVarargs 16.2 Java Logging API Basics: Logger, Levels, Handlers, and Configuration

2.1 Conditional Branching with if/else and the Ternary Operator

Key Takeaways Explain This Topic AI

Java if conditions strictly require expressions that evaluate to primitive boolean or boxed Boolean; integers (0, 1) and object references cannot be coerced to boolean.

In nested if/else statements without curly braces, an else clause binds to the nearest unmatched preceding if statement, creating the dangling-else trap.

Local variable declarations are prohibited as immediate unbraced child statements of if or else constructs and cause compile-time errors.

The ternary operator (? :) enforces binary numeric promotion and unboxing across its branches; pairing a boxed wrapper with a primitive can trigger unexpected runtime NullPointerExceptions if the wrapper is null.

A ternary expression produces a value and cannot stand alone as an expression statement without being assigned, returned, or passed as an argument.

Last updated: October 2026

2.1 Conditional Branching with if / else and the Ternary Operator

Decision-making constructs direct the path of code execution at runtime based on boolean conditions. While the fundamental structure of if , else if , and else statements appears straightforward, Java enforces strict type rules and parsing semantics that distinguish it from other C-family languages. The Oracle Java SE 17 Developer exam (1Z0-829) tests these subtleties, including strict boolean typing, the dangling else resolution mechanism, bracketless scoping hazards, and complex runtime type coercion in ternary expressions.

Strict Boolean Type Evaluation

In languages such as C, C++, or Python, non-boolean expressions such as integers ( 0 or 1 ) and object references ( null or non-null pointers) can evaluate to "truthy" or "falsy" values within conditional statements. Java does not support truthy or falsy conversions. The condition expression within an if statement must evaluate strictly to the primitive boolean type or its boxed wrapper java.lang.Boolean . int threshold = 10;

  • // COMPILE ERROR: incompatible types: int cannot be converted to boolean
  • if (threshold) {
  • System.out.println("Threshold reached");
  • }

String name = "Oracle";

  • // COMPILE ERROR: incompatible types: java.lang.String cannot be converted to boolean
  • if (name) {
  • System.out.println("Valid name");
  • }
  • The Assignment vs. Equality Trap

A frequent source of exam trick questions involves the assignment operator ( = ) mistakenly or intentionally placed inside a conditional expression instead of the equality comparison operator ( == ).

Because the assignment expression var = value returns the value being assigned, the type of the assignment determines whether the code compiles:

Numeric Assignment : An assignment like if (x = 5) assigns 5 to x and evaluates to the integer value 5 . Because an int cannot be converted to boolean , this produces a compile-time error.

Boolean Assignment : An assignment like if (isActive = true) assigns true to isActive and evaluates to the boolean value true . Because the expression yields a boolean , this code compiles and executes , taking the branch regardless of the variable's prior value! int count = 0;

// if (count = 1) { } // FAILS TO COMPILE: incompatible types: int to boolean

  • boolean hasPermission = false;
  • if (hasPermission = true) {

// COMPILES AND EXECUTES!

// hasPermission is assigned true, and the if-condition evaluates to true.

  • System.out.println("Access granted");
  • }

Warning

Watch out for boolean assignments in exam questions! Code like if (flag = false) compiles cleanly but evaluates to false , bypassing the if body and executing the else branch (if present). Always verify whether an operator in a condition is == or = .

Nested if Statements and the Dangling else Problem

When if and else statements are nested without explicit curly braces ( {} ), Java applies a deterministic grammatical rule: an else clause binds to the nearest preceding unmatched if statement within the same block .

Indentation and whitespace are completely ignored by the Java compiler. Misleading indentation can easily obscure how branches execute: int temperature = 32;

boolean isRaining = false;

  • if (temperature > 50)
  • if (isRaining)
  • System.out.println("Warm rain");
  • else
  • System.out.println("Cold weather");

Despite the indentation aligning the else clause with the outer if (temperature > 50) , the compiler attaches the else to the inner if (isRaining) . The execution proceeds as follows:

temperature > 50 ( 32 > 50 ) evaluates to false .

The outer if condition fails. Because the entire inner if-else construct forms the single subordinate statement of the outer if , the entire nested block is skipped.

Nothing is printed to the console!

  • To associate the else with the outer if , explicit curly braces are required: if (temperature > 50) {
  • if (isRaining) {
  • System.out.println("Warm rain");
  • }
  • } else {
  • System.out.println("Cold weather"); // Executes when temperature <= 50
  • }
  • Single-Statement Blocks and Local Variable Declarations

When omitting curly braces {} in an if or else branch, exactly one statement belongs to that branch. A critical rule governed by JLS §14.5 prohibits local variable declaration statements as the immediate child statement of an unbraced if , else , while , or for loop: boolean debug = true;

  • if (debug)
  • int counter = 100; // COMPILE ERROR: variable declaration not allowed here

The rationale for this restriction is semantic: a local variable declared in an unbraced statement would fall out of scope immediately at the subsequent semicolon, making the variable completely unreachable and unusable. To declare a local variable inside an if branch, curly braces must create a block scope: if (debug) {

  • int counter = 100; // Legal: scoped within the block
  • System.out.println(counter);
  • }

Similarly, omitting braces when multiple statements are intended results in subsequent statements executing unconditionally: int x = 20;

  • if (x < 10)
  • System.out.println("Small");
  • System.out.println("Always executed!"); // Executes regardless of x
  • The Ternary Operator ( ? : )

The ternary operator provides a concise conditional expression with the following syntax:

  • booleanExpression ? expression1 : expression2
  • Core Operational Rules

Short-Circuit Evaluation : Exactly one of the two branch expressions is evaluated at runtime. If booleanExpression evaluates to true , expression1 is evaluated and expression2 is skipped entirely. If booleanExpression evaluates to false , expression1 is skipped and expression2 is evaluated. Side effects (such as post-increments or method invocations) located in the skipped branch do not take place.

Expression vs. Statement : The ternary construct is an expression , not a statement . It produces a value and must be used where a value is accepted (assigned to a variable, returned from a method, or passed as a method argument). It cannot exist as an isolated statement: int score = 85;

// score > 50 ? System.out.println("Pass") : System.out.println("Fail"); // COMPILE ERROR: not a statement

// Legal usage:

  • String outcome = score > 50 ? "Pass" : "Fail";
  • System.out.println(score > 50 ? "Pass" : "Fail");
  • Type Unification and Unboxing Traps

The return type of a ternary expression is resolved at compile time through binary numeric promotion and reference type reconciliation. When the two operand expressions are of different types, the compiler determines a unified common type.

Numeric Type Promotion

If one operand is an int and the other is a double , the overall type of the ternary expression is promoted to double : int a = 5;

  • double b = 10.5;
  • var result = true ? a : b; // result is inferred as double; value is 5.0
  • The NullPointerException Unboxing Hazard

When mixing primitive types with boxed wrapper objects in a ternary expression, Java automatically unboxes the wrapper to match the primitive type. If the boxed reference is null , this automatic unboxing triggers a runtime NullPointerException ! Integer defaultLimit = null;

boolean useDefault = false;

// Numeric unboxing occurs: 100 is int, defaultLimit is Integer.

// The ternary expression unboxes defaultLimit via defaultLimit.intValue()!

Number selectedLimit = useDefault ? defaultLimit : 100; // Returns 100 safely

// However, when the condition selects the null operand:

Number dangerousLimit = !useDefault ? defaultLimit : 100;

// Throws java.lang.NullPointerException at runtime!

Even though dangerousLimit is declared as the abstract reference type java.lang.Number , the ternary operator inspects the types of both branches ( Integer and int ), recognizes that int requires unboxing of Integer , and evaluates defaultLimit.intValue() . Because defaultLimit is null , an unexpected NullPointerException occurs.

Warning

On the 1Z0-829 exam, watch for ternary expressions where one branch is a numeric primitive ( int , double , etc.) and the alternate branch is a boxed wrapper containing null . Unboxing rules take precedence over reference assignment, resulting in a runtime NullPointerException rather than assigning null .

Nested Ternary Expressions and Evaluation Order

Ternary operators are right-associative. When multiple ternary operators are chained without parentheses: int marks = 75;

String grade = marks >= 90 ? "A" : marks >= 75 ? "B" : marks >= 60 ? "C" : "F";

The expression parses from right to left as:

marks >= 90 ? "A" : (marks >= 75 ? "B" : (marks >= 60 ? "C" : "F"))

At runtime:

marks >= 90 is false .

The second expression marks >= 75 ? "B" : ... is evaluated.

marks >= 75 is true , yielding "B" . The remaining expressions are skipped.

Decision Constructs Comparison

  • Feature if / else if / else Ternary Operator ( ? : )
  • Syntactic Category Control flow statement Value-producing expression

Standalone Validity Can execute arbitrary statements, loops, blocks Must be assigned, returned, or passed as argument

  • Return Type None ( void ) Determined by type reconciliation of branches
  • Short-Circuiting Evaluates only chosen branch block Evaluates only chosen branch expression

Unboxing Hazards Only if explicitly unboxing in condition/body Implicit unboxing when mixing primitive and boxed operands

Brace Scoping Rules Requires {} for multiple statements and local variable declarations Not applicable; operates strictly on expressions