0Pricing
Java Academy · Lesson

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, Alice

Effectively 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 shorthand

Anonymous 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());       // 2

Anonymous 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

  1. Static Nested Classes
  2. Inner Classes and Outer Access
  3. Local and Anonymous Classes
  4. Choosing the Right Nesting Strategy
← Back to Java Academy