Understand Java Interface Default Methods
- Details
- Written by Nam Ha Minh
- Last Updated on 25 August 2019   |   Print Email
Since Java 8, an interface can have default methods with concrete implementation. This article helps you understand why default methods are needed and how to use them.
You know, Java 8 comes with some new features like Streams and Lambda expressions which require adding of some new methods in the core interfaces of the Java Collections framework. For example, the Collection interface needs to add two methods sort() and stream() - as illustrated in the following class diagram:
However, there are many sub interfaces and implementation classes in the Collection inheritance tree – so adding new methods to the Collection interface will break these existing classes – require them to implement the new methods. And worse, there are also countless of classes written by programmers that depend on the Collection inheritance tree – causing their applications to fail if the new methods added to Collection interface works the old way: concrete classes must implement methods declared in its super interfaces.
Therefore, the designers of Java language decided to introduce default methods for interface. A default method is declared with the default modifier before the return type, and it contains method body (implementation). For example, the new methods added to the Collection interface are declared as follows:
public interface Collection<E> { public default void sort() { // implementation goes here } public default Stream<E> stream() { // implementation goes here } // other abstract methods }
Since default methods must have code implementation, subclasses of the interface don’t have to implement them – keeping the existing code intact when new methods are added to the interface.
A subclass can use the inherited default methods, for example:
public interface A { void foo(); default void bar() { // code } } class AImpl implements A { public void foo() { //... bar(); //... } }
So the purpose of default methods is to make changes to existing interfaces without breaking its existing subclasses – for backward compatibility. That means you should not use default methods for completely new code. Use default methods to make changes to old code - existing interfaces – to avoid changes to existing implementation classes.
When a class implements an interface that contains default methods, it can:
- Do nothing: inherit the default methods from the super interface.
- Re-declare the default methods as abstract – causing its subclasses to implement them.
- Override the default methods with new implementation.
Default method and multiple inheritance in Java:
There can be a case in which a class implements two different interfaces having the same default method, for example:
public interface X { void foo(); default void bar() { // code } } public interface Y { void doo(); default void bar() { // code } } public class XYImpl implements X, Y { }
In this case, to avoid ambiguity, the sub class must override the common default method, for example:
public class XYImpl implements X, Y { public void foo() { // implement from X } public void doo() { // implement from Y } public void bar() { // override from X, Y } }
Default method and static method in interface in Java:
Also since Java 8, we can write static methods (with code body) in an interface. Imagine an interface has two default methods that use a same portion of code:
public interface ABC { void foo(); // abstract method default void bar() { // code snippet #1 // other bar's code } default void doo() { // code snippet #1 // other doo's code } }
Here, both the default methods bar() and doo() uses a same portion of code code snippet #1. We want to avoid code duplication – so how can we do?
Introduce a new default method that contains only the code to be reused? That’s possible. But the intermediate default method is also inherited by subclasses – adding more complexity to the inheritance tree - which we don’t want.
So instead of using an intermediate default method, we can write the shared code in a static method like this:
public interface ABC { void foo(); // abstract method static void code1() { // code snippet #1 } default void bar() { code1(); // other bar's code } default void doo() { code1(); // other doo's code } }
Since static methods do not belong to instances of class and are not inherited, they are perfect to be reused by default methods, as seen in the above example. But that’s not the only use of static method in interface.
So far you have learned about default methods in interface in Java. Adding default methods to an interface doesn’t break the existing code, hence interfaces in Java now can evolve over time.
Related Tutorials:
Other Recommended Tutorials:
- 9 Rules about Constructors in Java
- 12 Rules and Examples About Inheritance in Java
- 12 Rules of Overriding in Java You Should Know
- 10 Java Core Best Practices Every Java Programmer Should Know
- Understand abstraction in Java
- Understand encapsulation in Java
- Understand inheritance in Java
- Understand polymorphism in Java
Comments