Java 8 introduced default methods in interfaces. This post describes what they are, and how they can change the design of APIs.
A nominal design
Earlier, in Java, interfaces could only have contracts - method signatures with no implementation.
In order to add some implementation, a class was required, whether abstract or not.
Hence, traditional API design then followed this hierarchy:
- The root interface defines the contract
- An intermediate class implements common behavior i.e.
Bar
- If necessary, a class in the hierarchy overrides this behavior e.g.
Corge
A wrench in the works
This is perfect, until classes outside the reach of the API designer can implement the interface.
The following hierarchy describes the List
part of the Java Collections API, with an additional custom class:
Now, let’s introduce the sort()
method in the List
interface.
Only classes i.e. AbstractList
and MyList
can actually implement this method.
Obviously, it’s impossible to enforce the same sort()
implementation in both classes, even though it makes sense.
Direct implementations of List
have to duplicate (yuck!) the sort()
of AbstractList
.
In order to remove the duplication and DRY the design, Java API designers have moved the sort()
method out of List
to an unrelated class with only static
methods.
This resolves the common code issue, as there’s now only one single method responsible for sorting.
On the flip side, static
methods are not object-oriented.
Worse, there’s no relationship from List
to Collections
in the code (though there’s one in the opposite direction).
Hence, if one is not aware of the Collections
class and its features, there’s no way to know about it.
Default methods to the rescue
Now, imagine if it were possible to implement code in interface methods.
The sort()
method could be implemented in the List
interface.
The above class diagram would then look like that:
That would solve the above issue.
By default, every list implementation would be provided with the sort()
method by inheritance.
This is exactly the reason for default methods. No more, no less.
For curious reader, the
|
Conclusion
If you end up having to duplicate code in multiple classes instead of factoring it into a single common interface, a default method is a far more elegant solution than helper classes.