liveBook · Manning

Conditional logic

As explained in 100 Java Mistakes and How to Avoid Them

A branching statement is a Java control-flow statement that selects among alternative execution paths.

Conditional logic selects an execution path from a condition. In Java, `if–else` chains express ordered alternatives, while the conditional operator (`?:`) selects between two expressions. They can look interchangeable, but expression precedence, type conversion, and control-flow structure can make a compact rewrite behave differently. section 2.6 section 3.0

Treat a long `if–else if–else` sequence as one exclusive decision. Omitting an intermediate `else` silently starts a second chain: a successful earlier branch can run and then the later chain, including its final `else`, can run too. This is harmless only when independent execution is intended or conditions are mutually exclusive. section 3.1 section 3.12

Data data;
if (condition1) {
  data = getData1();
} else if (condition2) {
  data = getData2();
} else if (condition3) {
  data = getData3();
} else if (condition4) {
  data = getData4();
} else {
  data = getDefaultData();
}
process(data);

When every branch merely chooses data for the same later operation, assign that data in one complete chain and call the operation afterward. This makes an accidental split easier to spot; declaring the local variable `final` can make multiple assignment a compiler error. section 3.1

A conditional expression has low precedence. Without parentheses, surrounding addition or string concatenation may become part of its condition rather than part of a selected branch. A null check such as `"Value: " + value != null` tests the concatenated string, which is never null, not `value`. Split mixed expressions into intermediate variables, parenthesize deliberately, or use a library method such as `Math.max` where it states the intended calculation directly. section 2.2.2 section 2.2.3

Precedence changes a null fallback

The expression `"Value: " + value != null ? value : "(unknown)"` is parsed as `(("Value: " + value) != null) ? value : "(unknown)"`. Since concatenation produces a non-null string, the fallback is never selected. Choose the value first, then add the prefix: `String displayedValue = value != null ? value : "(unknown)"; return "Value: " + displayedValue;`. IntelliJ IDEA and SonarLint can flag this particular always-true condition, but similarly plausible precedence calculations may evade static analysis. section 2.2.3

Do not assume `condition ? thenValue : elseValue` has the same semantics as returning from two `if` branches. Conditional expressions determine one result type from both branches. With a boxed number and its corresponding primitive, the primitive can win, forcing unboxing before the result is boxed again. A null boxed value can therefore throw `NullPointerException` even when the method returns a wrapper type. section 2.6.1 section 2.6

Nested ternaries can unbox null

`return input > 20 ? 2 : input > 10 ? 1 : null;` appears to return `2`, `1`, or `null`, yet can unbox the nested `null` result because of type calculation across the branches. Reordering the conditions changes that calculation, which is a warning sign rather than a style to rely on. Prefer `if` statements for nested cases and avoid branches with different types, especially primitive and boxed numeric types. IntelliJ IDEA and PVS-Studio can report possible unboxing; a nesting warning alone does not prove the conversion is safe. section 2.6.2

Conditional expressions inside variable-arity calls have another trap. If one branch supplies a single value and another supplies an array, the expression as a whole may have type `Object`; the compiler then wraps it as one varargs argument, producing an extra array layer. Prefer the original `if` call structure, or make the selected argument shape explicit. IntelliJ IDEA’s Suspicious Ternary Operator in Varargs Method Call inspection targets this pattern. section 2.10

Use conditional logic defensively:

  • Keep `else if` chains visually and structurally complete when exactly one action must occur; test every branch. section 3.1 section 3.12
  • Parenthesize a conditional expression embedded in a larger expression, or extract it into a named local variable. section 2.2.2 section 2.2.3
  • Use `if` statements instead of nested ternaries or ternaries mixing primitive and boxed numeric branches. section 2.6.2
  • Review static-analysis findings, but do not expect analyzers to detect every malformed chain or plausible precedence calculation. section 2.2.2 section 3.1

How 100 Java Mistakes and How to Avoid Them covers it

How deep it goes
Explains precedence, varargs wrapping, boxing conversions, nested ternaries, and malformed chains, emphasizing prevention and selective static analysis.
Examples
Uses formatted printing, string indentation, null-value display, boxed-number mapping, and data-selection if–else chains.
What it assumes
Assumes Java familiarity while clarifying conditional-expression precedence, type conversion, and if–else control flow.
What you can do after
Diagnose/debug with it by recognizing branch-splitting, precedence, varargs, and boxing failures and choosing safer rewrites.
How it connects
Connects conditional logic to operator precedence, string concatenation, null checks, varargs, autoboxing, and static analysis.

Also explained in

Compare how 21 books explain conditional logic →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of 100 Java Mistakes and How to Avoid Them. The section links point to the parts of the book it draws on.