Back to Blog
Java

Java Anonymous Object: Syntax and Use Cases

Learn how to create anonymous objects in Java, when to use them, and how they compare with lambdas and named classes.

anonymous classesJava syntaxlambda expressionsinner classesevent listeners
Diagram showing an anonymous object in Java created from an interface, with a note about its one-time use.

What Is a Java Anonymous Object?

In Java, the phrase anonymous object can be used in two ways: an object created without assigning it to a variable, such as new Example().method(), or an instance of an anonymous class. This article focuses on the second meaning: an anonymous object is an instance of an anonymous class—a class defined and instantiated in a single expression, without a name. The syntax looks like this:

Runnable task = new Runnable() { @Override public void run() { System.out.println("Running task"); } };

Here, new Runnable() { ... } creates an object of an unnamed class that implements Runnable. The object is assigned to a variable of the interface type. Anonymous objects are useful when you need a one-off implementation of an interface or an extension of a class, and you don't want to create a separate named class.

Creating an Anonymous Object from an Interface or Abstract Class

You can create an anonymous object from any interface or abstract class, as long as you implement all required methods. For example, a Comparator for custom sorting:

List<String> names = Arrays.asList("Alice", "Bob", "Charlie"); names.sort(new Comparator<String>() { @Override public int compare(String a, String b) { return b.length() - a.length(); } });

The anonymous class implements Comparator<String> and provides the compare method. The object is passed directly to sort. This pattern is common when the comparison logic is only needed in one place.

You can also extend a concrete class and override methods:

Thread thread = new Thread() { @Override public void run() { System.out.println("Custom thread"); } };

Here, the anonymous object is an instance of a subclass of Thread. The class body defines the override.

Common Use Cases for Anonymous Objects

Anonymous objects appear frequently in event handling, callbacks, and functional-style operations. In Swing, for example, you often see:

button.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { System.out.println("Clicked"); } });

Before lambdas were introduced in Java 8, anonymous classes were the standard way to pass behavior. They are still used when the interface has multiple abstract methods (so it is not a functional interface) or when you need to override more than one method.

Another common case is initializing collections with custom behavior, such as a HashMap with an overridden put method for logging:

Map<String, Integer> map = new HashMap<String, Integer>() { @Override public Integer put(String key, Integer value) { System.out.println("Put " + key); return super.put(key, value); } };

This is a double-brace initialization, which creates an anonymous subclass of HashMap. It works, but it creates an extra class and carries the memory tradeoffs discussed below.

Anonymous Objects vs. Lambda Expressions

For functional interfaces—interfaces with a single abstract method—lambdas provide a more concise syntax. The Runnable example from earlier becomes:

Runnable task = () -> System.out.println("Running task");

Lambdas are not anonymous classes; they are implemented differently and have different this and scoping semantics. The following table summarizes the key differences:

AspectAnonymous ClassLambda Expression
SyntaxVerbose, requires full method definitionConcise, no method name
Type supportCan implement any interface or extend a non-final classOnly for functional interfaces
this referenceRefers to the anonymous objectRefers to the enclosing instance
Variable captureCan capture effectively final variablesCan capture effectively final variables
Generated bytecodeNew class file per anonymous classInvokedynamic with lambda metafactory

The this difference is important. Inside an anonymous class, this refers to the anonymous object; inside a lambda, this refers to the enclosing object. That also means an anonymous class has its own class scope, so it can declare fields and helper methods inside the expression. A lambda body does not create such a class body and cannot declare instance fields.

Variable Capture and Effectively Final Rules

Both anonymous classes and lambdas can only capture local variables that are effectively final—meaning they are not reassigned after initialization. This rule exists because local variables are captured by value when the anonymous class or lambda is created; if the variable were mutable, the captured copy could go stale.

int base = 10; Runnable r = new Runnable() { @Override public void run() { System.out.println(base); // OK, base is effectively final } };

If you try to reassign base anywhere after initialization, the compiler rejects the capture. The same restriction applies to lambdas.

Memory and Performance Considerations

Each anonymous class definition compiles to a separate .class file, such as OuterClass$1.class. This increases the number of class files in your application, which can affect startup time and memory footprint if used excessively. Additionally, an anonymous class created in an instance context holds an implicit reference to its enclosing instance, which can prevent garbage collection if the anonymous object outlives the enclosing object. This is a common source of memory leaks in long-lived applications.

For example, if you register an anonymous ActionListener from an instance method of an activity or frame, the listener keeps a reference to that enclosing instance. If the enclosing object is no longer needed, it cannot be collected because the listener still references it. Using a static nested class or a lambda that does not capture the enclosing instance avoids this problem.

Performance-wise, creating an anonymous object is similar to creating any other object. The overhead is in class loading and allocation, not in method calls. For high-frequency operations, reusing a single instance or using a non-capturing lambda, which the JVM may cache, can reduce allocation pressure.

Limitations and Maintainability Tradeoffs

Anonymous objects are best for small, one-off implementations. They become hard to read when the class body grows beyond a few methods. They also cannot have explicit constructors, so you cannot pass arguments to initialize state—you must rely on instance initializers or captured variables. If you need multiple instances with different configurations, a named class with a constructor is clearer.

Another limitation is that an anonymous class cannot be declared static. If it is created in an instance context, it has an implicit reference to the enclosing instance. This is rarely a problem for short-lived objects but can become a memory concern when the object is stored for a long time. In a static method, the anonymous class has no enclosing instance reference.

From a maintainability perspective, named classes are easier to test and reuse. If the same behavior is needed in multiple places, extract it into a named class. Anonymous objects are appropriate when the logic is trivial and tightly coupled to the surrounding code.

Java Anonymous Object: Syntax, Use Cases, and Lambda Comparison | RYUSLOG DEV