<code>@FunctionalInterface</code> in Java

@FunctionalInterface declares that an interface has exactly one abstract method. The compiler enforces this β€” if you add a second abstract method, compilation fails. The annotation is optional (any interface with one abstract method can be used as a lambda target), but making it explicit documents intent and catches future mistakes.

Declaring one

@FunctionalInterface
public interface Mapper<T, R> {
    R apply(T input);
}

// Usage β€” a lambda is an instance of a functional interface
Mapper<String, Integer> len = s -> s.length();
len.apply("hello");                // 5

What counts as "one abstract method"

  • Exactly one method without a body (the SAM β€” Single Abstract Method).
  • default methods don't count.
  • static methods don't count.
  • Methods inherited from Object (equals, hashCode, toString) don't count.
@FunctionalInterface
public interface Named<T> {
    String name();                               // the SAM
    default String pretty() { return "~ " + name() + " ~"; }   // OK β€” default
    static Named<Object> constant(String n) { return () -> n; }  // OK β€” static
    boolean equals(Object o);                    // OK β€” from Object
}

Common JDK functional interfaces

InterfaceMethodTypical use
Function<T,R>R apply(T)stream.map(...)
BiFunction<T,U,R>R apply(T,U)map.merge(...)
Consumer<T>void accept(T)list.forEach(...)
Supplier<T>T get()Optional.orElseGet(...)
Predicate<T>boolean test(T)stream.filter(...)
UnaryOperator<T>T apply(T)list.replaceAll(...)
Runnablevoid run()Threads, Executors
Comparator<T>int compare(T,T)list.sort(...)

When to declare your own

When the built-in types don't describe your domain well β€” for example, a RetryPolicy, a PriceRule, a Validator. Giving the interface a meaningful name makes call sites self-documenting compared to Function<Order, Decision>.

Method references

Function<String, Integer> a = String::length;           // unbound instance
Consumer<Object> b = System.out::println;                // bound instance
Supplier<User>   c = User::new;                          // constructor reference
Function<Integer, int[]> d = int[]::new;                 // array constructor

Common mistakes

  • Forgetting @FunctionalInterface β€” your interface still works as a lambda target today; a future second abstract method silently breaks every caller.
  • Extending Function to rename it β€” adds a type, doesn't add value. Use a type alias pattern only when the semantics differ.
  • Overloading generic functional methods β€” callers can't tell which type the lambda infers; resolution becomes ambiguous.

Related

Pillar: Java annotations. See also interfaces, methods.