Java
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax
-
Section 3: Object-Oriented Java
-
Section 4: Collections Framework
-
Section 5: Exception Handling
-
Section 6: Generics
-
Section 7: Functional Java
-
Section 8: Concurrency
-
Section 9: I/O and NIO
-
Section 10: JVM Internals
-
Section 11: Modern Java Features
-
Section 12: Build Tools and Project Structure
-
Section 13: Testing
-
Section 14: Databases and Persistence
-
Section 15: Networking
-
Section 16: Design and Best Practices
-
Section 17: Reflection and Annotations
-
Section 18: Logging and Diagnostics
-
Section 19: Date, Time, and Internationalization
-
Section 20: Java Platform Module System
-
Section 21: Security in Java
-
Section 22: Advanced Collections and Data Structures
-
Section 23: More Concurrency Patterns
-
Section 24: Compression, Files, and System Integration
-
Section 25: GUI Programming
-
Section 26: Practical Projects
-
Section 27: Data Structures and Algorithms
-
Section 28: Interview and Algorithm Practice
-
Section 29: JSON and Data Interchange
-
Section 30: More Concurrency Utilities
-
Section 31: More Collections and Streams Practice
-
Section 32: More File and System Programming
-
Section 33: Standard Library Deep Dive
-
Section 34: More Practice and Drills
-
Section 35: More Testing and Quality
-
Section 36: More Design Patterns and Architecture
-
Section 37: Career and Ecosystem
-
Section 38: More OOP and Architecture Practice
-
Section 39: More Enterprise Concepts
-
Section 40: Advanced JavaFX
-
Section 41: More Interview Practice
38: Anonymous Classes
Imagine you're running a busy kitchen. Most of the time, you have established roles: a Head Chef, a Sous Chef, and a Pastry Chef. These are your "named classes." You know exactly who they are, what their job description is, and you can call them by name whenever you need them.
But every once in a while, something weird happens. Maybe a food critic walks in and demands a very specific, one-time modification to a dish—like a garnish made of crystallized ginger that you've never served before. You don't need to hire a permanent "Crystallized Ginger Specialist" and add them to your official payroll just for this one plate. Instead, you just grab whoever is standing closest, tell them, "For the next five minutes, your only job is to do this one specific thing," and once the plate is gone, that "role" ceases to exist.
That's exactly what an anonymous class is in Java. It's a way to define a class and instantiate it at the exact same time, without giving it a name. You're basically telling Java, "I need an object that implements this interface (or extends this class), but I'm only going to use it right here, right now, so don't bother making me write a whole separate file for it."
Cutting Out the Middleman
Normally, if you have an interface called PaymentProcessor, you'd create a class like CreditCardProcessor that implements it. But what if you're writing a quick test or a one-off piece of logic that will never be reused anywhere else in your app? Creating a new .java file just for five lines of code feels like overkill. It clutters your project.
Check out how we can skip the formal class declaration using an anonymous class:
public interface PaymentProcessor {
void process(double amount);
}
public class CheckoutSystem {
public void completePurchase(double total) {
// Instead of creating a separate class file, we define the logic right here
PaymentProcessor oneTimeDiscountProcessor = new PaymentProcessor() {
@Override
public void process(double amount) {
System.out.println("Processing a special one-time promotional payment of: $" + (amount * 0.8));
}
};
oneTimeDiscountProcessor.process(total);
}
}
Notice the syntax: new PaymentProcessor() { ... }. It looks like you're trying to instantiate an interface (which Java usually forbids), but that curly brace at the end is the magic. It tells the compiler, "I'm actually defining a nameless class that implements this interface on the fly."
When This Actually Makes Sense
I've seen developers use anonymous classes for everything, and honestly, that's a mistake. If you find yourself copying and pasting an anonymous class in two different places, stop. You've just discovered a need for a real, named class.
The sweet spot for anonymous classes is when the implementation is so specific to the current context that it would be confusing to define it elsewhere. A classic example is adding a listener to a button in a GUI application. The logic for "what happens when this specific button is clicked" usually only belongs in the class that created the button. Defining a SubmitButtonClickHandler class in its own file just to call saveData() is just adding noise to your codebase.
The Trade-off With Scope
One thing to keep in mind: anonymous classes have a unique relationship with the variables around them. They can access variables from the enclosing scope, but only if those variables are effectively final. This means if you try to change a local variable from inside your anonymous class, Java will throw a compiler error.
I used to find this frustrating when I first started, but it's actually a safety feature. Since the anonymous class might be executed later (like in a separate thread), Java ensures that the value it's using hasn't shifted under its feet. If you need to change a value, you'll need to use an instance variable or an array/atomic wrapper, but for 90% of your one-off logic, this won't be an issue.
📋 Practical Task
The Character Power Ranking Sorter
You are building a game where players have a list of GameCharacter objects. Each character has a name and a powerLevel. You need to sort this list, but the sorting logic changes depending on the game mode. For this specific task, you need to sort the characters from highest power level to lowest.
Instead of creating a dedicated PowerLevelComparator class, implement a custom Comparator using an anonymous class to sort the list in descending order.
import java.util.*;
class GameCharacter {
String name;
int powerLevel;
GameCharacter(String name, int powerLevel) {
this.name = name;
this.powerLevel = powerLevel;
}
@Override
public String toString() {
return name + " (" + powerLevel + ")";
}
}
public class GameSorter {
public static void main(String[] args) {
List<GameCharacter> characters = new ArrayList<>();
characters.add(new GameCharacter("Warrior", 85));
characters.add(new GameCharacter("Mage", 92));
characters.add(new GameCharacter("Rogue", 78));
characters.add(new GameCharacter("Paladin", 88));
// TODO: Use Collections.sort() with an anonymous class
// that implements Comparator<GameCharacter>
// to sort characters by powerLevel in descending order.
System.out.println("Rankings: " + characters);
}
}There are no comments for now.