@FunctionalInterface Annotation in Java
Fast recall
Quick revision
Core answer
Understanding that @FunctionalInterface is optional but recommended
Thinking an interface MUST have @FunctionalInterface to be used as a lambda target
Mention that the annotation is optional for lambda targeting, while `Runnable`, `Callable`, and `Comparator` are themselves annotated in modern Java APIs
Interview-ready guide
Interview answer
@FunctionalInterface is optional. Lambda compatibility comes from the interface having one function method under Java's abstract-method rules, not from the annotation itself.
The annotation documents that intent and makes the compiler check it at the interface declaration. If someone adds a second independent abstract method, compilation fails there. Default and static methods are still allowed because they do not add another abstract requirement, and a method matching a public method of Object does not become the function method.
Runnable, Callable, and Comparator are useful library examples: the interfaces predate or were adapted for Java 8, and their current declarations carry @FunctionalInterface. An equivalent custom interface would still accept a lambda without the annotation, but adding it gives maintainers an immediate guardrail.
@FunctionalInterface Annotation in Java
Direct Answer
@FunctionalInterface is an optional annotation that tells the compiler to verify the interface has exactly one abstract method. It is NOT required — any interface with one abstract method can be used as a functional interface. The annotation just prevents accidental addition of a second abstract method.
Code Example
// WITHOUT annotation - still works as functional interface
interface PaymentProcessor {
void processPayment(double amount);
}
// WITH annotation - compiler enforces the rule
@FunctionalInterface
interface OrderProcessor {
void processOrder(Order order);
// Adding this would cause compile error with @FunctionalInterface
// void cancelOrder(Order order);
// Default methods are allowed - don't count as abstract
default void logProcessing(Order order) {
System.out.println("Processing: " + order.id());
}
}
record Order(Long id, double amount) {}
public class PaymentService {
public void executePayment(double amount, PaymentProcessor processor) {
processor.processPayment(amount); // Lambda works here
}
public static void main(String[] args) {
var service = new PaymentService();
// Both work with lambdas
service.executePayment(100.0, amt -> System.out.println("Paid: " + amt));
}
}
Common Mistakes & Pitfalls
- Thinking the annotation is required: lambda compatibility comes from the interface's method shape; the annotation validates and documents it.
- Claiming
RunnableorCallablelacks the annotation: their current Java declarations are annotated, even though the interfaces predate Java 8. - Counting every declaration mechanically: default and static methods do not add abstract requirements, and methods matching public
Objectmethods are handled specially. - Annotating a true multi-operation contract: if the interface needs several independent abstract methods, it is not a functional interface.
Check your understanding
Answer these without looking back at the article.
- Does Runnable have @FunctionalInterface?
- What happens if you add @FunctionalInterface to an interface with two abstract methods?
- Can an interface with no abstract methods be a functional interface?
Looking for a structured roadmap?
Every module on this page is also part of the full Java backend interview track.