Local Inner Class in Java – Classes Inside Methods
A local inner class (or simply local class) is a class declared inside a method, constructor or block. Like a local variable, it is visible only within that block. It can use the enclosing method's parameters and local variables, provided they are final or effectively final, and, when declared in an instance method, the members of the outer object.
This tutorial shows how to write local classes, the effectively-final rule, local records and interfaces (Java 16+), and how local classes compare with anonymous classes and lambdas.
1. Syntax
returnType method(params) {
class LocalClass { // no access modifier, no static
// fields, constructors, methods
}
LocalClass obj = new LocalClass(); // usable only after its declaration, in this block
}
2. Example: Invoice Lines
The Line class is needed only while building one invoice, so it is declared inside the method:
import java.util.ArrayList;
import java.util.List;
public class LocalClassBasics {
private final String currency = "INR";
String invoice(String customer, double[] amounts) {
double taxRate = 0.18; // effectively final local variable
// Local class: visible only inside this method
class Line {
final double net;
Line(double net) { this.net = net; }
double gross() { return net * (1 + taxRate); } // captures local variable
String format() { return String.format("%10.2f %s", gross(), currency); } // outer field
}
List<Line> lines = new ArrayList<>();
for (double a : amounts) lines.add(new Line(a)); // several instances
StringBuilder sb = new StringBuilder("Invoice for " + customer + "\n");
double total = 0;
for (Line l : lines) { sb.append(l.format()).append('\n'); total += l.gross(); }
return sb.append(String.format("Total: %.2f %s", total, currency)).toString();
}
public static void main(String[] args) {
System.out.println(new LocalClassBasics().invoice("Asha", new double[] {1000, 250.5, 99}));
}
}
Invoice for Asha
1180.00 INR
295.59 INR
116.82 INR
Total: 1592.41 INR
Linereads the local variabletaxRateand the outer fieldcurrency.- Unlike an anonymous class, a local class has a name, so you can create several instances and use it as a type (
List<Line>). - No code outside
invoice()can see or useLine.
3. The Effectively Final Rule
A local class may use the enclosing method's local variables and parameters only if they are never reassigned after initialisation:
public class EffectivelyFinalRule {
public static void main(String[] args) {
int count = 3; // effectively final: never reassigned
String label = "item";
class Printer {
void print() {
for (int i = 1; i <= count; i++) System.out.println(label + " " + i);
}
}
new Printer().print();
// count++; // uncommenting this makes 'count' not effectively final:
// compile error "local variables referenced from an inner class
// must be final or effectively final"
}
}
item 1 item 2 item 3
The local class captures a copy of each variable's value when an instance is created. Requiring the variable to be unchanging guarantees that the copy and the original never disagree. Fields of the outer object, by contrast, are accessed through the outer reference and can change freely.
4. Local Records, Enums and Interfaces (Java 16+)
Since Java 16 you can also declare records, enums and interfaces locally. They are implicitly static, so they cannot capture local variables or the outer instance:
import java.util.List;
public class LocalClassValidation {
static List<String> validate(String username, String password) {
int minLength = 8;
// A named local class used for two checks in this method only
record Rule(String name, boolean passed) {
String report() { return (passed ? "PASS " : "FAIL ") + name; } // local record (Java 16)
}
interface Check { boolean test(String s); } // local interface (Java 16)
Check hasDigit = s -> s.chars().anyMatch(Character::isDigit);
return List.of(
new Rule("username not blank", !username.isBlank()),
new Rule("password length >= " + minLength, password.length() >= minLength),
new Rule("password has a digit", hasDigit.test(password))
).stream().map(Rule::report).toList();
}
public static void main(String[] args) {
validate("asha", "secret").forEach(System.out::println);
System.out.println("--");
validate("ravi", "secret123").forEach(System.out::println);
}
}
PASS username not blank FAIL password length >= 8 FAIL password has a digit -- PASS username not blank PASS password length >= 8 PASS password has a digit
Local records are handy for intermediate results, for example in stream pipelines, without polluting the class with a type nobody else needs.
5. Rules of Local Classes
- No access modifiers (
public,private…) and nostatic; they may befinalorabstract. - Visible only in the block where they are declared, and only after the declaration.
- Can access enclosing local variables and parameters only if final or effectively final.
- In an instance method, can access all outer members; in a static method, only outer static members.
- Since Java 16 they can declare static members.
- Compiled to files such as
Outer$1Line.class.
6. Local Class vs Anonymous Class vs Lambda
| Aspect | Local class | Anonymous class | Lambda |
|---|---|---|---|
| Has a name | Yes | No | No |
| Multiple instances / use as a type | Yes | One expression | One expression |
| Constructors and several methods | Yes | No constructors; methods yes | One method only |
| Can extend a class | Yes | Yes | No (functional interfaces only) |
| Best for | Non-trivial helper used several times in one method | One-off implementation with state or several methods | Single-method behaviour |
7. When to Use a Local Class
- A helper type is needed only inside one method and would clutter the class if declared as a member.
- You need more than an anonymous class offers: a constructor, multiple instances or a name to refer to.
- Local records are ideal for grouping temporary values.
If the class grows large or is needed elsewhere, promote it to a private static nested class.
8. Summary
- A local class is declared inside a method or block and visible only there.
- It can use effectively final locals and, in instance methods, the outer object's members.
- It has a name, so it can be instantiated many times, unlike an anonymous class.
- Java 16 added local records, enums and interfaces, which are implicitly static.
Related Tutorials
Frequently Asked Questions (FAQ)
Q1. What is a local inner class in Java?
A class declared inside a method, constructor or block, visible only within that block.
Q2. Can a local class access local variables?
Yes, but only those that are final or effectively final.
Q3. What does effectively final mean?
A variable that is never reassigned after it is initialised, even though it is not declared final.
Q4. Can a local class have access modifiers?
No. It cannot be public, protected, private or static, but it can be final or abstract.
Q5. Can a local class be used outside its method?
The class name is not visible outside, but an instance can be returned as a supertype, such as an interface it implements.
Q6. Can a local class have static members?
Since Java 16, yes. Earlier versions allowed only static constants.
Q7. Can a local class access outer class fields?
Yes, if declared in an instance method. In a static method it can access only the outer class's static members.
Q8. What is the difference between a local class and an anonymous class?
A local class has a name, can have constructors and can be instantiated many times. An anonymous class is unnamed and created exactly where it is declared.
Q9. Can I declare an interface inside a method?
Yes, since Java 16. Local interfaces, enums and records are implicitly static.
Q10. Can a local record capture local variables?
No. Local records are implicitly static, so they cannot use the enclosing method's variables or the outer instance.
Q11. What is the compiled file name of a local class?
Outer$1Local.class, where the number distinguishes local classes with the same name in different methods.
Q12. Can a local class extend another class?
Yes. It can extend a class and implement interfaces like any other class.
Q13. Why must captured variables be effectively final?
The local class stores copies of their values. If the variables could change, the copies would become inconsistent with the originals.
Q14. Can a local class be declared inside a static method?
Yes. It then has no outer instance and can access only static members of the enclosing class.
Q15. Can a local class be declared in a loop or if block?
Yes. Its scope is that block.
Q16. Can I modify a captured variable through a workaround?
You can capture a mutable object (such as an array or AtomicInteger) and change its contents, but this is often a sign that a field or return value would be clearer.
Q17. Are local classes common in modern Java?
Local classes are fairly rare; lambdas cover most short cases. Local records, however, are increasingly popular for temporary data.
Q18. Can a local class be generic?
Yes. It can declare its own type parameters and use type parameters of the enclosing method.
Q19. Does a local class hold a reference to the outer object?
If declared in an instance context, yes, like other inner classes. Local records, enums and interfaces do not.
Q20. When should I convert a local class to a nested class?
When it becomes long, needs to be tested independently, or is needed by more than one method.