A Sneak Peek of Default Methods in Java 8

Lochana Ranaweera
Lochness Writes
Published in
4 min readNov 16, 2015

So far I have discussed some of the “code changers” brought about by Java 8 such as lambda-expressions, variable scope changes, and method references. Today I will be explaining another cool feature in Java 8 called default methods.

Prior to Java 8, Interfaces could contain only constants and method signatures, where method signatures are method definitions without method bodies. Java 8 introduces the concept of default methods and static methods, allowing for interface methods to include a concrete implementation.

So why do we need default methods?

Traditionally, adding new functionality to interfaces was considered unacceptable in Java. This was because whenever an interface gets new methods, then every program written using that interface will break until it too is fixed to implement those methods.

Let’s take a look at an example:

The code below shows how the class ExampleClass implements the interface ExampleInterface. Interface ExampleInterface has an abstract method greetSomeone. To implement the interface above, the class ExampleClass must provide an implementation of the method greetSomeone.

/**
* Created by lochana
*/
interface ExampleInterface {public void greetSomeone(String name);
}
public class ExampleClass implements ExampleInterface {@Override
public void greetSomeone(String name) {
System.out.println(“Hello “ + name);
}
}
public class MainClass {public static void main(String[] args) {ExampleClass greetingObject = new ExampleClass();
greetingObject.greetSomeone(“Loch”);
}
}

Output:

Hello Loch

Let’s say we want to add a generic greeting function to our interface. To do so, if I proceed and include another method greetAnyone in the interface as an abstract method, the compiler would give an error until the class ExampleClass is changed to provide an implementation of the method greetAnyone.

How can we add new functionality to interfaces without breaking the previous code?

Now with JDK 8, we can overcome the issue of having to break already written code when introducing new functionality to interfaces. All you have to do is define the method greetAnyone as a default method by using the keyword default followed by a concrete implementation at interface level as follows.

/**
* Created by lochana
*/
interface ExampleInterface {public void greetSomeone(String name);default void greetAnyone() {
System.out.println(“Hello there!”);
}
}
public class ExampleClass implements ExampleInterface {@Override
public void greetSomeone(String name) {
System.out.println(“Hello “ + name);
}
}
public class MainClass {public static void main(String[] args) {ExampleClass greetingObject = new ExampleClass();
//greetingObject.greetSomeone(“Loch”);
greetingObject.greetAnyone();
}
}

Output:

Hello there!

Notice that with the addition of the method greetAnyone as a default method, I did not have to change my previous code in the class ExampleClass. Default methods provide us with the flexibility to allow methods to be implemented in interfaces. Some may not see as a good practice as it “pollutes” the interface code. But this has allowed Java as a language, to integrate some powerful function expressions especially in the Collections library such as the forEach method.

Conflicts?

Of course, as for any other keyword, you should be careful when using the default keywords to include default methods at the interface level.

Let us now take a look at what happens if the exact same method is defined as a default method in one interface and then again as a method of a superclass or another interface?

Rules for resolving ambiguities:

  1. Superclasses always win.
  2. Interfaces clash and must be resolved manually.

Rule #1, is quite simple. If a superclass provides an implementation, the default method with the same name and parameter types are simply ignored. Rule #2 is applicable in a situation where two or more interfaces have a default method with the same signature hence thereby causing a conflict as the compiler cannot figure out which method to call.

Let’s take a look at a conflict due to multiple interfaces:

In the following example there are two default methods with the same name. Therefore below code gives an compilation error saying, “class ExampleClass inherits unrelated defaults for greetAnyone() from types ExampleInterfaceOne and ExampleInterfaceTwo”.

/**
* Created by lochana
*/
interface ExampleInterfaceOne {default void greetAnyone() {
System.out.println(“Hello there, Earthling!”);
}
}
interface ExampleInterfaceTwo {default void greetAnyone() {
System.out.println(“Hello there, Martian!”);
}
}
public class ExampleClass implements ExampleInterfaceOne, ExampleInterfaceTwo {}

In order resolve this conflict, you will have to manually provide an implementation for the greetAnyone method in the class ExampleClass either by overriding both the methods in interfaces ExampleInterfaceOne and ExampleInterfaceTwo or specifically invoking one of them. I have specifically invoked the greetAnyone method from ExampleInterfaceOne in my corrected code shown below.

/**
* Created by lochana
*/
interface ExampleInterfaceOne {default void greetAnyone() {
System.out.println(“Hello there, Earthling!”);
}
}
interface ExampleInterfaceTwo {default void greetAnyone() {
System.out.println(“Hello there, Martian!”);
}
}
public class ExampleClass implements ExampleInterfaceOne, ExampleInterfaceTwo {@Override
public void greetAnyone() {
ExampleInterfaceOne.super.greetAnyone();
}
}

Doubts?

Sometimes you might be confused about the difference between an abstract class and an interface with default methods, as both have similar behavior. The difference between an abstract class and a Java 8 supported interface with default methods is that the interface will not inherit Object class methods whereas an abstract class would. Interfaces have default methods for “backward compatibility”. That is we can add new methods to an interface without affecting previously written classes that implement the particular interface.

--

--