Local Variables in Java

A local variable is declared inside a method, constructor, or block. It's visible only within that block and disappears when the block exits. Unlike fields, local variables have no default value β€” you must assign one before you read it, or the compiler rejects the code.

Declaration

public void process(List<String> items) {
    int count = 0;                         // initialise on declaration
    StringBuilder sb = new StringBuilder();

    for (String s : items) {
        String upper = s.toUpperCase();    // scoped to the for body
        sb.append(upper);
        count++;
    }
    // `upper` is gone here
}

Definite assignment

int x;
System.out.println(x);      // ❌ compile error β€” "variable x might not have been initialized"

int x;
if (cond) x = 1;
System.out.println(x);      // ❌ still rejected β€” not assigned on every path

int x;
if (cond) x = 1; else x = 2;
System.out.println(x);      // βœ… every path assigns

Type inference with var (Java 10+)

var list   = new ArrayList<String>();     // ArrayList<String>
var reader = Files.newBufferedReader(p);   // BufferedReader
var i      = 0;                            // int
var s      = "hello";                      // String

var works only on locals with an initialiser β€” not on fields, method parameters, or return types. See the var page for details.

Effectively final β€” the lambda rule

String prefix = "hello ";
list.forEach(s -> System.out.println(prefix + s));   // βœ…

String prefix = "hello ";
prefix = "hi ";
list.forEach(s -> System.out.println(prefix + s));   // ❌ captured, must be effectively final

Any local captured by a lambda or inner class must be effectively final β€” not reassigned after initialisation, even without the keyword.

Scope vs lifetime

Scope is where the name is visible (lexical β€” defined by the enclosing block). Lifetime is how long the value lives β€” usually the same, but a value referenced by an escaping lambda can outlive the block.

Naming and placement

  • Use descriptive names: retryCount over i (unless it's a loop index).
  • Declare at first use, not at the top of the method β€” keeps related code together.
  • Prefer many small scopes over one long method with 20 locals in flight.

Common mistakes

  • Reading an uninitialised local β€” the compiler catches this. Initialise on declaration.
  • Shadowing a field with a local of the same name β€” accidental. Use this.field or rename.
  • Using var where the type is unclear β€” the reader shouldn't have to jump to the right-hand side.

Related

Pillar: Variables in Java. See also var, final.