When use and when not to use default methods in Java interfaces
Java 8 introduces many new useful features; unfortunately, it also leads to new misunderstandings and antipatterns being observed every day. One of these mistakes is the incorrect use of default methods in interfaces.
I have noticed that programmers often implement default methods with an implementation that is valid only for some production subclasses or even for none of them (a default implementation is used only in tests). For example, a default method might return an empty string or an empty list, and all production subclasses override it.
The general rule for using default methods in interfaces is similar to the principle governing the use of implemented methods in abstract classes. The default implementation should be appropriate for all subtypes. For example:
-
Since Java 8, the List class has a
sort
method. Its implementation is valid for all subtypes, but subtypes likeSingletonList
orSynchronizedList
override this implementation. -
If you create an interface
Car
with a methodgetName
, it is OK to create a default implementation that returns the string"Car"
. This implementation is valid for theFord
class, which implements theCar
interface. However, thegetName
method may be overridden to return a string containing the car model, such as"Ford " + model
.
Default methods are powerful tools when used with lambda expressions and functional interfaces. They are also very useful when you would like to add methods to an interface in a library code and preserve backward compatibility. However, default methods should never provide invalid behavior.