Java 8: Default & Static Interface Methods - Similar, but different!

So Java 8 has officially been out for almost 4 years now, and with it came a variety of cool stuff. Some were improvements to the language like Parallel array sorting and more efficient collision resolution in HashMaps. New features included the ever so popular Lambdas and Method Parameter Reflection (For those bad-ass developers). One new feature in particular is the ability to have Default and Static Interface Methods (Static interface methods were actually included in previous versions of Java, but we shall include them for comparison). This article aims to explain what they are with using a variety of examples.

1. Intro to Default & Static Interface Methods

In EC -1(example code 1, shown below), we see a simple interface declaration. The two methods within the interface perform the exact same operation, however one is default and the other is static.

//EC-1: Intro to default and static interface methods
public interface Foo {
//Default method declaration
default int sumDefault(int a, int b) {
return a + b; //simply adds a + b
}
    //Static method declaration
static int sumStatic(int a, int b) {
return a + b; //simply adds a + b
}
}

IntelliJ or whichever IDE you’ve configured to use Java-8 shouldn’t complain about the above. Let’s delve deeper!

2. Implementing the Foo Interface

If we try implement the Foo interface as shown in EC-1 without overriding any of the methods, our IDE will not complain because it knows an implementation has already been provided as shown in EC-2 below.

EC-2: Implementing Foo
public class Bar implements Foo {
//No implementation required as it is already provided in the interface. IDE remains happy :D.
}

3. Invocation

Let us see how we can invoke both default and static interface methods.

EC-3: Invoking default & static methods.
//Default
int i = new Bar().sumDefault(2, 2);
System.out.println("Default: " + i);
//Static    
int i = Foo.sumStatic(2, 2);
System.out.println("Static: " + i);

As shown in EC- 3, we can simply invoke the default method as if it were any other instance method in the class i.e, by calling the classes constructor new <Constructor>.<method> as it already has an implementation.

On the other hand, since static methods belong to the class/interface template, they can be invoked the same way any static method is normally invoked i.e <Class/Interface>.<method> . Both of the examples in EC-3 are error free.

4. Overriding the default and static methods in the Foo Interface

What happens when we try override both the default and static method?

EC-4: Overriding Default & Static Interface Methods
public class Bar implements Foo {
@Override
public int sumDefault(int a, int b) {
return a + b - 1; // adds a + b then subtracts 1
}

@Override <- Error
public int sumStatic(int a, int b) {
return a + b - 1; // adds a + b then subtracts 1
}
}

As shown in EC-4, overriding the default method will work without a hitch. We unfortunately cannot override static methods, as Java prevents overriding any method with the keyword static. Your IDE will point out the error.

Let’s see how to invoke default and static interface methods that have been are overridden. We will build on the code from EC-4.

5. Invoking Overridden Methods

Since static methods cannot be overridden we shall only focus on default methods for this example.

EC-5: Invoking default and static interface methods
public class Bar implements Foo {
@Override
public int sumDefault(int a, int b) {
return a + b - 1;
//Note this overridden version adds a to b then subtracts 1;
//The original interface method just adds a to b;
}

public static void main(String args[]) {
Bar bar = new Bar();
int i = bar.sumDefault(2, 2);
System.out.println("Default: " + i);
}
}
Output:
Default: 3
#QuickMaths

The output of sumDefault after overriding it is 3 instead of 4. This shows that default methods when overridden will take on the implementation of the class they were overridden in, and not persist their base Interface implementation.

6. Implementing Multiple Interfaces

Implementing multiple Interfaces is something we all do, but what if two interfaces contain the same default method signature? Consider this new interface we shall call Goo

EC-6 Implementing Foo and Goo
public interface Goo {
//Exact same method signature as that of Foo
default int sumDefault(int a, int b) {
return a + b + a; //Adds a + b and then adds a again, unlike Foo that just adds a + b;
}
}
public class Bar implements Foo, Goo {
//Which implementation of sumDefault(int a, int b) will this class use, Foo or Goo????
}

EC-6 poses a great question. Which implementation will class Bar take? The answer is … None of them! Your IDE will complain saying Bar inherits unrelated versions of the method sumDefault(int a, int b). As a developer, you will have to ignore both of them and implement your own version. In this case it’s like having a traditional Interface that requires you to define your own implementation of the method.

7. Lastly implementing a hierarchy of interfaces.

For our last example what would happen if Goo extended from Foo, and Bar implemented Goo as shown in EC-7 below

EC-7: Implementing a hierarchy of interfaces
public interface Foo {
default int sumDefault(int a, int b) {
return a + b; // Adds a to b
}
}

public interface Goo extends Foo {
default int sumDefault(int a, int b) {
return a + b - 1; //Adds a + b, then subtracts 1.
}
}

public class Bar implements Goo {
public static void main(String args[]) {
System.out.println("Default: " + new Bar().sumDefault(2, 2));
}
}
Output:
Default: 3
#MoreQuickMaths

As you can see from EC-7, the output is always the most recent implementation down the chain. So we can forget about the implementation provided by Foo as it has been overridden by that of Goo .

Conclusion

So there you have it, a little intro to how Default and Static Interface methods can be used. In my opinion these are pretty profound additions to the world of Java. One question I would like to pose is, If Interfaces now have the ability to define an overridable implementation for methods, where does that leave Abstract Classes? I mean Abstract Classes still have the ability to set instance variables and define constructors. However beyond that, the new default keyword seems to narrow that divide between Abstract classes and Interface, by allowing Interfaces to define their own implementation of methods that can be overridden downstream.

As with most new features there will be good use cases for it, as Pankaj from JournalDev notes, “Java interface default methods will help us in removing base implementation classes, we can provide default implementation and the implementation classes can chose which one to override.”, I appreciate the added flexibility we now have.

Thanks for reading!