Java 9 – Diamond Operator (<>) with Anonymous Inner Classes
The diamond operator <> was introduced in Java 7 to eliminate the redundancy of repeating type parameters when creating generic instances. In Java 8, there was a notable limitation: you could not use the diamond operator with anonymous inner classes. Java 9 lifts this restriction, making anonymous class syntax cleaner and more consistent with regular instantiation.
Quick Recap: What is the Diamond Operator?
// Without diamond (pre-Java 7) – verbose, type repeated twice
List<String> names = new ArrayList<String>();
// With diamond (Java 7+) – compiler infers the type
List<String> names = new ArrayList<>();
The diamond operator tells the compiler "infer the generic type parameter from the left side." This is purely a compile-time feature; the generated bytecode is identical.
The Java 8 Limitation with Anonymous Classes
In Java 8, the diamond operator was not allowed with anonymous inner classes:
// Java 8 – this FAILS to compile with diamond operator
Comparator<String> comp = new Comparator<>() { // <-- compile error in Java 8!
@Override
public int compare(String a, String b) {
return a.compareTo(b);
}
};
// Java 8 workaround – had to write the type explicitly
Comparator<String> comp = new Comparator<String>() {
@Override
public int compare(String a, String b) {
return a.compareTo(b);
}
};
The reason Java 8 disallowed this was that anonymous classes can expose internal types that aren't accessible outside the anonymous class body — a subtle inference problem the Java 8 compiler didn't handle. Java 9 resolved this.
Java 9 – Diamond Operator Works with Anonymous Classes
package com.java9r;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
/**
* Java 9 – Diamond operator with anonymous inner classes.
*/
public class DiamondOperatorJava9 {
// A generic abstract class for demonstration
abstract static class Processor<T> {
abstract T process(T input);
}
public static void main(String[] args) {
// --- Comparator with diamond (Java 9+) ---
Comparator<String> byLength = new Comparator<>() { // works in Java 9
@Override
public int compare(String a, String b) {
return Integer.compare(a.length(), b.length());
}
};
var words = new ArrayList<>(List.of("Banana", "Apple", "Fig", "Strawberry", "Kiwi"));
words.sort(byLength);
System.out.println("Sorted by length: " + words);
// --- Anonymous Comparator in sort call ---
words.sort(new Comparator<>() {
@Override
public int compare(String a, String b) {
return a.compareToIgnoreCase(b); // alphabetical
}
});
System.out.println("Sorted alphabetically: " + words);
// --- Generic abstract class with diamond ---
Processor<String> upperCase = new Processor<>() {
@Override
public String process(String input) {
return input.toUpperCase();
}
};
System.out.println("\nProcessed: " + upperCase.process("hello java 9"));
// --- Diamond with generic interface ---
var numComparator = new Comparator<Integer>() {
@Override
public int compare(Integer a, Integer b) {
return b - a; // descending
}
};
// Java 9 allows: new Comparator<>() as well
var numbers = new ArrayList<>(List.of(5, 3, 8, 1, 9, 2, 7));
numbers.sort(numComparator);
System.out.println("\nNumbers descending: " + numbers);
}
}
Expected Output
Sorted by length: [Fig, Kiwi, Apple, Banana, Strawberry]
Sorted alphabetically: [Apple, Banana, Fig, Kiwi, Strawberry]
Processed: HELLO JAVA 9
Numbers descending: [9, 8, 7, 5, 3, 2, 1]
Anonymous Classes vs Lambda Expressions
Since Java 8, lambda expressions can replace single-method functional interfaces, making anonymous classes less common. However, anonymous classes are still needed when:
- The interface has multiple abstract methods
- You need to maintain state (fields) in the anonymous class
- You are extending an abstract class (not just implementing an interface)
- You need to override methods from
Object(liketoString())
// Lambda – fine for single-method functional interfaces
Comparator<String> lambdaComp = (a, b) -> a.compareTo(b);
// Anonymous class – needed for stateful behavior
Comparator<String> statefulComp = new Comparator<>() { // Java 9 diamond
private int callCount = 0; // stateful – lambdas can't have fields
@Override
public int compare(String a, String b) {
callCount++;
return a.compareTo(b);
}
};
Diamond Operator Rules (Java 9)
- The diamond
<>works with anonymous classes in Java 9+ - The type is still inferred from the declared variable type on the left side
- If the anonymous class introduces new type variables not present in the outer type, inference fails and you must use explicit types
- Lambda expressions are still preferred over anonymous classes for functional interfaces
Before and After Java 9
| Scenario | Java 7–8 | Java 9+ |
|---|---|---|
| Regular instantiation | new ArrayList<>() ✓ |
new ArrayList<>() ✓ |
| Anonymous class | new Comparator<String>() {} (must be explicit) |
new Comparator<>() {} ✓ |
Summary
Java 9 made the diamond operator consistent by allowing it with anonymous inner classes. This is a small but welcome improvement that removes the inconsistency between regular instantiation and anonymous class creation. In practice, most uses of anonymous classes with functional interfaces can be replaced with lambdas. But when you do need an anonymous class — for stateful behavior, multiple-method interfaces, or abstract class extension — the diamond operator now works cleanly in Java 9 and later.
Comments