Back to results for “Design Patterns in Java”
Java › Interfaces & Abstract Classes

How would you use an interface with only static and default methods (no abstract methods at all) to build a fluent, extensible utility API, and what's a real JDK example of this pattern?

Advanced

Answer

An interface can consist entirely of static and default methods, with zero abstract methods at all, functioning essentially as a namespace-scoped collection of utility methods (via its static methods) plus optional 'mixin'-style shared behavior (via default methods) that other interfaces or classes can incorporate by extending/implementing it -- java.util.function's Function interface itself demonstrates this pattern well beyond its core single abstract method (apply()), providing static identity() and default andThen()/compose() methods that together build a rich, fluent, extensible utility API around that one core abstract method, without needing a separate, disconnected FunctionUtils-style utility class.
public interface MathOperations {
    static double square(double x) { return x * x; }        // pure utility, no abstract method needed
    static double cube(double x) { return x * x * x; }

    default double squareThenDouble(double x) {  // could combine with an eventual abstract method if added later
        return square(x) * 2;
    }
}

double result = MathOperations.square(5);  // called directly via the interface name, like a utility class
Real-world example The JDK's Comparator interface combines its one core abstract method (compare()) with a rich set of default methods (thenComparing(), reversed()) and static factory methods (comparing(), naturalOrder()), together forming a comprehensive, fluent API entirely within the interface itself, a design pattern many custom libraries have since adopted for their own functional-style interfaces.

Common follow-ups: What's the practical difference between this static-and-default-heavy interface pattern and simply using a traditional final utility class with private constructor and only static methods?;Why might a library choose an interface-based utility API over a traditional utility class specifically to enable future extensibility?