This rule raises an issue when you create an anonymous inner class that implements a functional interface (an interface with exactly one abstract method). In Java, these anonymous inner classes should be replaced with lambda expressions, which provide a cleaner and more concise syntax for the same functionality.
A single-method interface is a type that defines exactly one abstract behavior contract. In Java, these are called functional
interfaces. Common examples include Runnable, Callable, Comparator, and the interfaces in the
java.util.function package.
Before Java 8 introduced lambda expressions, the only way to implement a functional interface inline was through verbose anonymous inner classes. This approach requires significant boilerplate code that obscures the actual logic:
taskVariable = new InterfaceImplementation() {
@Override
public void methodName() {
processData();
}
};
Java 8 introduced lambda expressions specifically to simplify this pattern. A lambda expression is a concise way to represent a functional interface using an expression. The same functionality can be written as:
taskVariable = () -> processData();
Using lambda expressions instead of anonymous inner classes offers several benefits:
@Override annotations.The conversion from anonymous inner class to lambda expression is straightforward because the compiler can infer the interface type from the context. This type inference is what makes lambda expressions so concise.
Note that this conversion may require judgment in some cases. When the anonymous class references its own this keyword, the semantics
change in a lambda (see "How to fix it" below). Similarly, when the target type is ambiguous due to method overloading, additional casts or type hints
may be needed.
This rule does not apply when the anonymous class is intentionally kept for readability (e.g., complex multi-statement bodies where a lambda would hurt clarity), when framework constraints require a named type, or when the anonymous class defines additional methods or fields beyond the single abstract method.
This rule does not raise an issue in the following cases:
this or super, because this in a lambda refers to the enclosing class, not
the lambda itself.Serializable explicitly), because lambda serialization has
different semantics and caveats.In Java, these single-method interfaces are called functional interfaces. Common examples include Runnable,
Callable, Comparator, and the many interfaces in the java.util.function package. Lambda expressions were
introduced in Java 8 as the standard syntax for implementing functional interfaces concisely.
When you use lambda expressions instead of anonymous inner classes:
Using older verbose syntax for defining inline behavior instead of modern concise functional syntax makes the code more verbose and harder to read. While this doesn’t affect the runtime behavior or security of the application, it impacts code maintainability. Developers spend more time reading and understanding unnecessarily complex code, which slows down development and increases the likelihood of introducing errors during modifications.
Replace the anonymous inner class with a lambda expression. The lambda syntax uses parameters in parentheses, an arrow ->, and the
method body. For single-expression bodies, you can omit the braces and return keyword.
When the lambda body is a single method call, consider using a method reference instead (e.g., this::processData or
System.out::println). Method references can be even more concise than lambdas and make the intent clearer.
Note that this inside an anonymous inner class refers to the anonymous class instance, while this inside a lambda refers
to the enclosing class. Before converting, check whether the anonymous class uses this to reference its own instance. If it does, the
conversion will change behavior and should not be applied mechanically.
Runnable task = new Runnable() {
@Override
public void run() {
System.out.println("Processing...");
}
}; // Noncompliant
Runnable task = () -> System.out.println("Processing...");