This tutorial explains what are default methods in Java 8 with examples, why they are useful and how they can be used to enhance the design of your code.
A little background: Prior to Java 8 interfaces could not have any implemented code. Methods defined in an interface for a type were considered to be the API methods for that type and any classes implementing that API had to implement all the methods. Well, the API part is still true in Java 8 i.e. interfaces will act as APIs for your design. However, interfaces can have implemented code in Java 8. These can be written in 2 ways – static methods & default methods. I have dealt with static methods in a separate articleClick to Read Tutorial on Java 8’s Static vs Default Methods. This article will focus on default methods.
What are Default Methods
Default methods are methods implemented in an interface, are non-abstract, and marked by the modifier default
. These methods are available to all classes which implement this interface.
Format of default methods
Inside an interface we need to mark a default method with the modifier default
as shown in example below –
//MyInterface.java public interface MyInterface{ default void printHello(){ System.out.println("Hello Default"); } } //MyInterfaceImpl.java public class MyInterfaceImpl implements MyInterface{ public static void main(String args[]){ new MyInterfaceImpl().printHello(); } }
MyInterface
implements a default methodprintHello()
.- Method
printHello()
is implemented to simply print"Hello Default"
. MyInterfaceImpl
class implementsMyInterface
- In the main method of
MyInterfaceImpl
whenprintHello()
method is invoked on an instance ofMyInterfaceImpl
then it calls the default implementation ofprintHello()
and prints"Hello Default"
How are default methods Useful
Default methods are useful in a big way for API designers and indirectly for API implementors. Lets see how. Lets say we define an interface for a group of handheld devices called DeviceAPI
. It has methods like getOS()
, getMaxResolution()
and getBrand()
– all abstract. Our interface DeviceAPI
would then look like this –
public interface DeviceAPI{ public String getOS(); public String getMaxResolution(); public String getBrand(); }
Now, over a period of time many devices are rolled out and for each new device we implement the DeviceAPI
interface and hence, we also implement all the abstract methods. Its all going fine when we come to know that a wearable device has come out which needs to have a check for whether bluetooth is enabled on the device.
We promptly write a method isBlueToothEnabled()
in the interface DeviceAPI
. But then we notice that DeviceAPI
has had more than a few, infact 20-30 implementations, many of these implementations were done by device vendors using this API and we have no access to their source code. If we go ahead and add this new method isBlueToothEnabled()
to DeviceAPI
, everything will be fine for the vendors till they do not recompile their implementation class along with the new DeviceAPI
. Then their code will start failing as compiler will not find the new method in their implementation. Secondly, we will have to change all of the 20-30 implementations. Even though that device maybe a wearable type of device or not.
How to overcome the issue of adding a new functionality to the API without breaking the code
Till Java 7 this kind of new functionality was very difficult to introduce due to the problems we noted above. But in Java 8 we have a solution for this. We can implement this isBlueToothEnabled()
method as a default method in DeviceAPI
. This implementation will then automatically be available to all the classes which implement DeviceAPI
.
The code for DeviceAPI
with the default method would look like this –
public interface DeviceAPI{ default boolean isBlueToothEnabled(){ //default method implementation goes here } public String getOS(); public String getMaxResolution(); public String getBrand(); }
Default methods as optional
To continue with the previous example, our design was good and default methods solved the problem. However, many device vendors complained that their classes were unnecessarily getting this new method isBlueToothEnabled()
. Vendors complain to us that their maintenance engineers may end up using this method as they might miss reading the documentation around this method. Basically, vendors want this method to be available if they need it, else they do not want to support this method for their devices.
As owners of DeviceAPI
we then tweak the default implementation of isBlueToothEnabled()
method to the one shown below –
public interface DeviceAPI{ default boolean isBlueToothEnabled(){ throw new UnsupportedOperationException(); } public String getOS(); public String getMaxResolution(); public String getBrand(); }
isBlueToothEnabled()
is the default method. However, it does not contain any implementation.isBlueToothEnabled()
by default throwsUnsupportedOperationException
.- Any class which implements
DeviceAPI
will not be forced with a default implementation if they do not need it. By default, this new operationisBlueToothEnabled()
will be unsupported. - Only when an implementation class really needs the
isBlueToothEnabled()
method they will override this method and write their own version - A default method written in the above way thus becomes optional.
Default Methods and multiple inheritance
A class can implement multiple interfaces and each of these interfaces can have default methods. Then this becomes an instance of multiple inheritance which was till Java 7 not possible in Java while it was possible in languages such as C++. Multiple inheritance in Java 8 using default methods is a topic on its own and I have written a separate tutorial on it here – multiple inheritance tutorialClick to Read Tutorial on Multiple Inheritance in Java 8.
Summary
This concludes the tutorial on default methods where we understood what are default methods, how we implement default methods in Java 8 interfaces, what kind of a basic design extensibility default methods solve,had a look at making default methods optional and lastly saw that default methods enable multiple inheritance in Java.
