W3docs

Java Local Classes

Declare classes inside method bodies in Java with local inner classes, with access to effectively-final locals.

A local class is a class declared inside a method body (or a constructor, or an initializer block). It's scoped to the block it's declared in — nothing outside that block can mention it by name. Otherwise it acts much like an inner class, with access to the enclosing instance's members and to the method's effectively-final locals.

Local classes are rare in modern Java. Lambdas have replaced their main use cases for one-method callbacks, and anonymous classes are usually shorter for one-off implementations. But a local class is occasionally the cleanest option when you need a named type that participates in the enclosing method's logic and isn't useful anywhere else.

If you have not met the other members of the nested-class family yet, the nested classes overview and inner classes chapters set up the terms used below.

Declaring one

A class declaration sitting inside a method body:

public void process(List<String> lines) {
  class Counter {
    int n = 0;
    void inc() { n++; }
  }

  Counter c = new Counter();
  for (String s : lines) if (!s.isBlank()) c.inc();

  System.out.println("non-blank lines: " + c.n);
}

Outside process, nobody can see Counter — its name doesn't exist beyond the method's closing brace. Inside, you use it like any other class.

Why pick it over an anonymous class?

A local class has a real name, which buys you a few things an anonymous class can't have:

  • A constructor. You can give it parameters, write validation, and have multiple constructors.
  • Multiple instances. Since the class has a name, you can write new Counter() more than once. An anonymous class definition only creates one instance per expression.
  • Self-reference. Counter can take itself as a parameter, hold a Counter next field, recurse — all the things named types can do.
  • Readability. A name like Counter documents what the helper is for. Anonymous new Object() { ... } blocks are harder to skim.

Access to enclosing state

Local classes can:

  • Read and write fields of the enclosing instance (if the enclosing method is non-static).
  • Call instance methods of the enclosing class.
  • Read — but not reassign — the enclosing method's final or effectively final local variables and parameters.
void run(int multiplier) {
  class Scaler {
    int scale(int x) { return x * multiplier; }   // captures the parameter
  }
  System.out.println(new Scaler().scale(7));
}

multiplier is captured into the synthetic class as a field. The "effectively final" requirement is the reason — if multiplier could be reassigned inside run after Scaler had captured its old value, the two would silently disagree.

In a static method

In a static method, the local class is implicitly static — it has no enclosing instance to refer to:

public static int demo() {
  class Helper {
    int square(int n) { return n * n; }
  }
  return new Helper().square(7);
}

There's no Outer.this here, because the enclosing method is static. Helper can still capture effectively-final locals from demo, just not instance fields of an enclosing object that doesn't exist.

When to actually use one

Concrete cases where a local class genuinely beats the alternatives:

  • The helper has more than one method, and you'd rather see the methods grouped together with a clear name than spread across anonymous-class boilerplate.
  • The helper needs a constructor to validate its setup.
  • The helper recurses or holds references to other instances of its own type.

If a lambda or short anonymous class would do, prefer that. Local classes are a niche tool.

Modifiers

A local class accepts only a narrow set of modifiers:

  • final — marks the class as non-extendable. It already has no name for outside code to extend, so this is mostly a statement of intent.
  • abstract — legal but rare: you would need a second local class in the same block to extend it.
  • Access modifiers (public, protected, private) are not allowed. A local class lives entirely inside one block, so there is no scope outside that block from which visibility could even be controlled.

It also cannot be declared static directly. Whether it captures an enclosing instance depends on whether the surrounding method is static, as shown above — not on a keyword.

A worked example

java— editable, runs on the server

What's next

That wraps up the nested-class tour — and most of Java's classical OOP machinery. The next section of Part 6 moves into the special class kinds: types Java provides for specific shapes of data, starting with enum for fixed sets of constants. Continue to Java enums.

Practice

Practice
Why might you choose a local class over an anonymous class for the same job?
Why might you choose a local class over an anonymous class for the same job?
Was this page helpful?