Local and Anonymous Classes
Declare classes inside methods and create anonymous implementations of interfaces on the fly.
Local and Anonymous Classes is a free Java Academy lesson on CoddyKit — lesson 3 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the Java Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.
Local and Anonymous Classes
Local classes are defined inside a method. Anonymous classes are local classes with no name — they combine class declaration and instantiation. Both capture effectively-final local variables.
Local Class Declaration
A local class is declared inside a method body. It can access the enclosing class members and effectively-final local variables.
static void greet(String language) {
// Local class — defined inside the method
class Greeter {
String sayHello(String name) {
// Can access 'language' — it is effectively final
return switch (language) {
case "EN" -> "Hello, " + name;
case "ES" -> "Hola, " + name;
case "FR" -> "Bonjour, " + name;
default -> "Hi, " + name;
};
}
}
Greeter g = new Greeter();
System.out.println(g.sayHello("Alice"));
}
greet("ES"); // Hola, AliceEffectively Final Variables
Local and anonymous classes can only capture local variables that are effectively final — they are never reassigned after initialization.
void process(int threshold) {
// threshold is effectively final (never reassigned)
Runnable r = new Runnable() {
public void run() {
System.out.println("Threshold: " + threshold);
}
};
r.run();
// threshold = 10; // If you add this, the anonymous class won't compile
}Anonymous Class Basics
An anonymous class implements an interface or extends a class inline, in one expression.
interface Comparator<T> {
int compare(T a, T b);
}
// Anonymous class implementing Comparator
java.util.Comparator<String> byLength = new java.util.Comparator<String>() {
@Override
public int compare(String a, String b) {
return Integer.compare(a.length(), b.length());
}
};
List<String> words = new ArrayList<>(List.of("banana", "fig", "apple", "kiwi"));
words.sort(byLength);
System.out.println(words); // [fig, kiwi, apple, banana]Anonymous vs Lambda
For single-abstract-method (SAM) interfaces, lambdas replace anonymous classes. Anonymous classes are still needed for interfaces with multiple methods or when extending abstract classes.
// Anonymous class for single-method interface
Runnable r1 = new Runnable() {
public void run() { System.out.println("Running!"); }
};
// Lambda — cleaner for SAM interfaces
Runnable r2 = () -> System.out.println("Running!");
// Must use anonymous class for multi-method interface:
java.io.FilenameFilter filter = new java.io.FilenameFilter() {
public boolean accept(java.io.File dir, String name) {
return name.endsWith(".java");
}
}; // FilenameFilter is not a SAM — no lambda shorthandAnonymous Class with State
Anonymous classes can have fields, unlike lambdas. This is useful when you need to maintain state within the anonymous implementation.
interface Counter { int increment(); int get(); }
Counter counter = new Counter() {
private int count = 0;
public int increment() { return ++count; }
public int get() { return count; }
};
System.out.println(counter.increment()); // 1
System.out.println(counter.increment()); // 2
System.out.println(counter.get()); // 2Anonymous Listener Pattern
Before lambdas, anonymous classes were the standard pattern for event listeners in GUI and Android programming.
// Modern Android/Swing style: anonymous class listener
Button loginButton = new Button(); // hypothetical
loginButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick() {
System.out.println("Login button clicked!");
}
});
// Modern equivalent with lambda (if OnClickListener is SAM):
loginButton.setOnClickListener(() -> System.out.println("Clicked!"));Local Class for Complex Logic
Local classes work well when you need a class with multiple methods only in one place — too complex for a lambda but too specific for a top-level class.
static List<String> processData(List<String> data, String prefix) {
// Local class: complex enough for a class, used only here
class DataProcessor {
List<String> result = new ArrayList<>();
void process(String item) {
// prefix is effectively final
if (item.startsWith(prefix)) {
result.add(item.toUpperCase());
}
}
}
DataProcessor dp = new DataProcessor();
data.forEach(dp::process);
return dp.result;
}
System.out.println(processData(List.of("apple","avocado","banana"), "a"));
// [APPLE, AVOCADO]Anonymous Class for Abstract Class
Anonymous classes can extend abstract classes, overriding abstract methods without creating a named subclass.
abstract class ReportFormatter {
abstract String formatHeader(String title);
abstract String formatBody(List<String> rows);
String format(String title, List<String> rows) {
return formatHeader(title) + "\n" + formatBody(rows);
}
}
ReportFormatter csvFormatter = new ReportFormatter() {
public String formatHeader(String t) { return "\"" + t + "\""; }
public String formatBody(List<String> rows) {
return String.join("\n", rows);
}
};
System.out.println(csvFormatter.format("Sales", List.of("a,1","b,2")));Double-Brace Initialization Anti-Pattern
The double-brace initialization trick uses anonymous classes for collection initialization. It creates a subclass with an instance initializer. Avoid it — it is inefficient and error-prone.
// Anti-pattern: double-brace initialization
Map<String, Integer> map = new HashMap<String, Integer>() {{
put("a", 1);
put("b", 2);
}};
// Creates an anonymous HashMap subclass — wasteful!
// GOOD: use Map.of() or Map.ofEntries()
Map<String, Integer> better = Map.of("a", 1, "b", 2);
// Or a mutable map:
Map<String, Integer> mutable = new HashMap<>(Map.of("a", 1, "b", 2));Choosing: Lambda vs Anonymous vs Local
Decision guide:
- Lambda: single abstract method, no extra state, no inheritance
- Anonymous class: multiple methods, needs state, or extends abstract class
- Local class: needs reuse within the method, multiple methods, complex state
Quick Check
What does an anonymous class always do in a single expression?
Recap: Local and Anonymous Classes
Key takeaways:
- Local classes are defined inside methods and can access effectively-final local variables
- Anonymous classes combine class declaration and instantiation in one expression
- Anonymous classes can have fields and multiple methods — unlike lambdas
- Lambdas replace anonymous classes for single-abstract-method interfaces
- Use local classes when logic is complex enough for a class but specific to one method
- Avoid double-brace initialization — it creates unnecessary anonymous subclasses
Frequently asked questions
Is the “Local and Anonymous Classes” lesson free?
Yes — the full text of “Local and Anonymous Classes” is free to read here on the web, and the Java Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the Java Academy course, upgrade to CoddyKit PRO.
What will I learn in “Local and Anonymous Classes”?
Declare classes inside methods and create anonymous implementations of interfaces on the fly. You practise Java Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.
Do I need any experience to start Java Academy?
No prior experience is required. Java Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 3 of 4, so you can start here or from the beginning and move at your own pace.
How long does the “Local and Anonymous Classes” lesson take?
Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.
Can I write and run code in this Java Academy lesson?
Yes. Every Java Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.
All lessons in this course
- Static Nested Classes
- Inner Classes and Outer Access
- Local and Anonymous Classes
- Choosing the Right Nesting Strategy