What is definite assignment in Java, and why does the compiler reject reading a local variable that might be unassigned?
answer
- Locals have no default; fields do
- DA = assigned on EVERY path before a read
- Compile-time, structural, conservative
- Constant expressions (true/false) are special-cased
- Only reads are constrained, not assignments
basics
~20 sDefinite assignment is a compile-time check that every local variable is given a value before you read it. If the compiler can find any path where the variable might not be set yet, it refuses to compile and reports a "variable might not have been initialized" error.
solid answer
~40 sDefinite assignment is a static analysis the Java compiler runs to guarantee that every local variable has a definitely-assigned value at the point it is read. Unlike fields, locals get no default value, so reading an unset local would expose garbage; the language forbids it at compile time instead. The compiler tracks, for each program point, whether a variable is "definitely assigned" along every possible execution path leading there. If any path could reach a read without an assignment, you get a compile error. This makes a whole class of uninitialized-variable bugs impossible. The analysis is conservative and path-based: it works on the structure of the code (if/else, loops, try/catch, switch), not on actual runtime values, so it can occasionally reject code that would in practice always assign.
go deeper
Knows locals must be initialized before use and that the compiler enforces it, recognizes the "might not have been initialized" error.
Can explain the every-path requirement, distinguishes locals from fields, and knows the check is compile-time and conservative.
Articulates that the analysis is structural/path-based per JLS, special-cases constant expressions, and applies to blank finals; can predict when the compiler will reject seemingly-fine code.
Frames it as a safety invariant of the type/flow system, contrasts with languages lacking it, and can discuss the trade-off between conservatism and false rejections, plus its interaction with final and exceptions.
## What problem this solves In Java a **local variable** (a variable declared inside a method, constructor, or block) does **not** receive a default value. Compare this with **fields** (variables declared at class level), which are automatically initialized to `0`, `false`, `null`, etc. If locals also silently defaulted, you could accidentally read a variable you forgot to set and get meaningless data. To prevent that entire bug category, the Java Language Specification (JLS, the official rulebook for the language) requires that a local variable be **definitely assigned** before any access that reads its value. ## What "definitely assigned" means At every point in the program, the compiler classifies a variable as either *definitely assigned* (DA) or *not*. A variable is DA at a given point if **every possible execution path** that reaches that point has already executed an assignment to it. "Every path" is the key phrase: it is not enough for *some* branch to assign the variable — *all* branches that can reach the read must. ```java int x; if (cond) { x = 1; } System.out.println(x); // ERROR: if cond is false, x is unassigned here ``` The `else` path (cond false) reaches the `println` without assigning `x`, so `x` is **not** definitely assigned there, and the compiler rejects it. ```java int x; if (cond) { x = 1; } else { x = 2; } System.out.println(x); // OK: every path assigns x ``` Now both branches assign `x`, so after the `if/else` it is definitely assigned. ## It is static and conservative The analysis runs at **compile time** and looks only at the *shape* of the code — the control-flow structure — never at the runtime values of variables. So it is **conservative**: it may reject code that, by human reasoning, would always assign the variable. ```java int x; if (true) { // a true constant: the compiler DOES special-case this x = 1; } System.out.println(x); // OK only because `true` is a constant expression ``` The compiler does evaluate **constant expressions** (`true`, `false`, `1 == 1`) when deciding reachability, but it will not reason about an ordinary boolean variable whose value it cannot know statically. ## Reading vs. assigning The rule only constrains a variable's **use as a value (a read)**. Assigning a value is always fine; declaring is fine. So: ```java int x; // declaration only — fine x = compute(); // assignment — fine int y = x; // read of x — requires x be definitely assigned (it is) ``` ## Where it applies Definite assignment governs **local variables** and **blank `final` fields/parameters** (finals with no initializer). It does **not** apply to ordinary non-final fields, because those have language-defined defaults. The rules cover all control structures — `if`, `while`, `for`, `do`, `switch`, `try/catch/finally`, the conditional operator `?:`, `&&`/`||`/`!`, `break`/`continue`/`return`/`throw` — each with its own JLS rule for how DA flows through it. ## Why it matters This check turns a common runtime mistake (using an uninitialized value) into an immediate compile-time error, with zero runtime cost. It is one of the reasons Java programs rarely exhibit the "reading garbage memory" bugs familiar from languages where locals are not checked.
- Do fields need definite assignment too?Ordinary (non-final) fields don't — they get default values (0/false/null). Blank final fields and blank final locals/parameters DO require definite assignment before use, and final fields additionally require definite *unassignment* before assignment.
- Why doesn't the compiler just default locals to 0/null like fields?It's a deliberate design choice: forcing explicit initialization catches "forgot to set it" bugs at compile time. A silent default would hide those bugs and make code intent ambiguous.
It's like a checklist at airport security: every passenger (every code path) must show a boarding pass (an assignment) before they reach the gate (the read). It is not enough that most passengers have one.
saying these in an interview costs you the question
- Saying locals default to 0/null like fields — they don't, that's the whole point
- Claiming the check inspects runtime values — it is purely static/structural
- Thinking an assignment in just one if-branch is enough
- Confusing definite assignment (must be set before read) with definite unassignment (final must NOT be set yet)