Interface Default Method in Java 8

Interface Default Method in Java8

Default method in interface

As you know that an Interface in java can have only Abstract methods and a class, which implements interface must provide implementation of all abstract methods or the class must be declared abstract.

If there is an old interface, which has multiple implementation classes and I want to improve the interface by adding a new method (new functionality), it will break all existing implementations. Existing implementation classes must change and implement new method. That’s what happens before Java 8.

Java 8 introduced Interface Default Method, which is very helpful in situation like above. Default method in interface allows providing default implementation of new method in interface itself. Default implementation is applicable to existing implementation classes, which do not implement new method. Implementation class can implement new method and override default implementation.

Calculator.java
public interface Calculator {
    int add(int a, int b);
    int subtract(int a, int b);
}

Here is implementation of Calculator interface

ClassicCalculator.java
public class ClassicCalculator implements Calculator {

    @Override
    public int add(int a, int b) {
        return (a + b);
    }

    @Override
    public int subtract(int a, int b) {
        return (a - b);
    }
}

Lets use ClassicCalculator

MainApp.java
public class MainApp {

    public static void main(String[] args) {
        Calculator classicCalculator = new ClassicCalculator();
        
        System.out.println("ClassicCalculator: 2 + 3 = " + classicCalculator.add(2, 3));
        System.out.println("ClassicCalculator: 10 - 4 = " + classicCalculator.add(10, 4));
    }
}

/* 
--- Output ---
ClassicCalculator: 2 + 3 = 5
ClassicCalculator: 10 - 4 = 14
*/

Lets add a new method multiply in Calculator interface. Mark new method as default method using default keyword and provide default implementation. Default implementation throws exception indicating operation is not supported. With the default method existing ClassicCalculator will work fine.

Calculator.java
public interface Calculator {
    int add(int a, int b);
    int subtract(int a, int b);
    
    default int multiply(int a, int b) {
         throw new RuntimeException("Operation not supported. Upgrade to UltimateCalculator");
    }
}
MainApp.java
public class MainApp {

    public static void main(String[] args) {
        Calculator classicCalculator = new ClassicCalculator();
        
        System.out.println("ClassicCalculator: 2 + 3 = " + classicCalculator.add(2, 3));
        System.out.println("ClassicCalculator: 10 - 4 = " + classicCalculator.add(10, 4));
        System.out.println("ClassicCalculator: 10 * 4 = " + classicCalculator.multiply(10, 4));
    }
}

/* 
--- Output ---
ClassicCalculator: 2 + 3 = 5
ClassicCalculator: 10 - 4 = 14
Exception in thread "main" java.lang.RuntimeException: Operation not supported. Upgrade to UltimateCalculator
    at com.readtorakesh.java8.interface_default_method.Calculator.multiply(Calculator.java:8)
    at com.readtorakesh.java8.interface_default_method.MainApp.main(MainApp.java:10)
*/

Lets write another implementation of Calculator interface which implements new multiply method as well.

UltimateCalculator.java
public class UltimateCalculator implements Calculator {

    @Override
    public int add(int a, int b) {
        return (a + b);
    }

    @Override
    public int subtract(int a, int b) {
        return (a - b);
    }

    @Override
    public int multiply(int a, int b) {
        return (a * b);
    }
}

Lets use UltimateCalculator and not output of multiple method.

MainApp.java
public class MainApp {

    public static void main(String[] args) {
        Calculator ultimateCalculator = new UltimateCalculator();
        
        System.out.println("UltimateCalculator: 2 + 3 = " + ultimateCalculator.add(2, 3));
        System.out.println("UltimateCalculator: 10 - 4 = " + ultimateCalculator.add(10, 4));
        System.out.println("UltimateCalculator: 10 * 4 = " + ultimateCalculator.multiply(10, 4));
    }
}

/* 
--- Output ---
UltimateCalculator: 2 + 3 = 5
UltimateCalculator: 10 - 4 = 14
UltimateCalculator: 10 * 4 = 40
*/

Static method in interface

Starting Java 8 interface can also have static method. Like static method of a class, static method of an interface can be called using Interface name.

Lets add a static method display in Calculator interface.

Calculator.java
public interface Calculator {
    int add(int a, int b);
    int subtract(int a, int b);
    
    default int multiply(int a, int b) {
         throw new RuntimeException("Operation not supported. Upgrade to UltimateCalculator");
    }
    
    static void display(String value) {
        System.out.println(value);
    }
}

Lets call display static method.

MainApp.java
public class MainApp {

    public static void main(String[] args) {
        Calculator ultimateCalculator = new UltimateCalculator();
        
        Calculator.display("UltimateCalculator: 2 + 3 = " + ultimateCalculator.add(2, 3));
        Calculator.display("UltimateCalculator: 10 - 4 = " + ultimateCalculator.add(10, 4));
        Calculator.display("UltimateCalculator: 10 * 4 = " + ultimateCalculator.multiply(10, 4));
    }
}

/* 
--- Output ---
UltimateCalculator: 2 + 3 = 5
UltimateCalculator: 10 - 4 = 14
UltimateCalculator: 10 * 4 = 40
*/

Default method and multiple inheritance

Java does not allow a class to extend multiple classes but a class can implement multiple interfaces. If a class implement two interfaces and both interfaces define default method of same signature, the implementation class must override default method and either provide new implementation or it call default method of either of the interfaces. To call default method of a particular interface it can use InterfaceName.super.method(…) syntax.

SampleInterface1, SampleInterface2 and SampleImplClass
interface SampleInterface1{
    default void showMethod() {
        System.out.println("SampleInterface1.showMethod()");
    }
}

interface SampleInterface2{
    default void showMethod() {
        System.out.println("SampleInterface2.showMethod()");
    }
}

class SampleImplClass implements SampleInterface1, SampleInterface2 {

    @Override
    public void showMethod() {
        //call default method of SampleInterface1
        SampleInterface1.super.showMethod();
    }
    
}
MainApp.java
public class MainApp {

    public static void main(String[] args) {
        new SampleImplClass().showMethod();
    }
}

/* 
--- Output ---
SampleInterface1.showMethod()
*/

Abstract Class versus Interface with default method

  1. Abstract class is more constructive in nature. It can have constructor but Interface can’t.
  2. Abstract class can be stateful. It can have member variables but Interface can’t
  3. Main purpose of Interface Default Method is to enhance existing interface without breaking existing implementations. We should not practice using default method for new interfaces. For new development always use Abstract Class instead of Interface with default method

Please share it and help others if you found this blog helpful. Feedback, questions and comments are always welcome.

Further Reading

Reference

https://docs.oracle.com/javase/tutorial/java/IandI/defaultmethods.html

1 Comment

Comments