@FunctionalInterface, Object methods and the 4-step check¶
โ Java 17 ยท The One-Method Contract Behind Every Lambda ยท 2/3
A functional interface has exactly one abstract method, counting inherited ones and ignoring those with a body. Two more details complete the rule.
@FunctionalInterface guards the contract¶
@FunctionalInterface
public interface PlayerControl {
void pause();
void resume(); // โ compiler error: two abstract methods
}
@FunctionalInterface
public interface PlayerControl {
void pause();
default void resume() { } // โ
only one abstract method
}
- The annotation asks the compiler to check the rule, and fail if it's broken.
- It doesn't create anything: an interface with one abstract method is functional with or without it.
- It documents your intent: nobody can add a second abstract method later and silently break every lambda using it.
The Object loophole¶
Every class extends Object, so every implementing class already has toString(), equals(Object) and hashCode(). An interface that redeclares them doesn't make anyone implement anything new:
public interface ContentFilter {
String toString();
boolean equals(Object o);
int hashCode();
boolean accept(Content c); // the only method that counts
}
ContentFilter kids = c -> c.ageRating() <= 7; // โ
still functional
Look-alikes that do count¶
The signature must match Object's exactly:
public interface SeriesMatcher {
boolean equals(Series s); // โ not Object's equals: a new abstract method
boolean match(Series s);
}
equals(Series) isn't equals(Object), so SeriesMatcher has two abstract methods. Two more cases:
- An interface that only redeclares
toString()has zero abstract methods that count: not functional. int toString();doesn't compile at all: it clashes withObject'sString toString().
The 4-step check¶
- List every abstract method, inherited ones included.
- Cross out methods with a body:
default,static,private. - Cross out exact public
Objectmethods:String toString(),boolean equals(Object),int hashCode(). - Exactly one left? It's functional, and a lambda can implement it.
The annotation never decides; the count does. @FunctionalInterface only makes the compiler run this check for you.
The lab builds a functional interface with a helper default method, and plugs different rules into one browse method.