Skip to content

@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 with Object's String toString().

The 4-step check

  1. List every abstract method, inherited ones included.
  2. Cross out methods with a body: default, static, private.
  3. Cross out exact public Object methods: String toString(), boolean equals(Object), int hashCode().
  4. 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.

๐Ÿ’ป Code: Java17_Part_8_Functional_Programming on GitHub

โ† Functional interfaces ยท Next: the lab โ†’