Imagine a bacon-wrapped Ferrari. Still not better than our free technical reports.
See all our reports

Java 8 explained: Default Methods

UPDATE: Since releasing this post, we’ve published a full Rebel Labs report entitled Java 8 Revealed: Lambdas, Default Methods and Bulk Data Operations. Click on the button below to get the full report!

Get the complete Rebel Labs report



In a previous post, we looked into lambdas in Java 8 which proved to be a very popular topic. Now we continue our peek into new Java 8 features by continuing with default methods. Those are closely related to lambdas, which could be the main theme of Java 8. In this article, we’ll take a look at what default methods are, what are the gotchas in using the default methods and how to apply the new feature in your daily life.

Why default methods?

Java 8 is approaching and even though the deadline has been pushed back, we can be quite confident that it will bring lambdas when it is finally out. As stated above, we did already cover the subject a bit some time ago, however, lambdas alone are not the only game-changer in Java 8.

Suppose Java 8 is out and has lambdas. Now you would like to start using lambdas and the most obvious use case for that is to apply a lambda to every element of a collection.

List<?> list = …
list.forEach(); // lambda code goes here

The forEach isn’t declared by java.util.List nor the java.util.Collection interface yet. One obvious solution would be to just add the new method to the existing interface and provide the implementation where required in the JDK. However, once published, it is impossible to add methods to an interface without breaking the existing implementation.

So it’d be really frustrating if we had lambdas in Java 8 but couldn’t use those with the standard collections library since backwards compatibility can’t be sacrificed.

Due to the problem described above a new concept was introduced. Virtual extension methods, or, as they are often called, defender methods, can now be added to interfaces providing a default implementation of the declared behavior.

Simply speaking, interfaces in Java can now implement methods. The benefit that default methods bring is that now it’s possible to add a new default method to the interface and it doesn’t break the implementations.

In my opinion, it doesn’t seem to be the language feature that would be appropriate to use every day, but it seems to be essential for Java Collections API update to be able to use lambdas naturally.

Download the Full Report (pdf)

Defenders 101

The most trivial example

Let’s start with the simplest example possible: an interface A, and a class Clazz that implements interface A.

public interface A {
    default void foo(){
       System.out.println("Calling A.foo()");
    }
}
 
public class Clazz implements A {
}

The code compiles even though Clazz does not implement method foo(). Method foo() default implementation is now provided by interface A.

And the client code that users the example:

Clazz clazz = new Clazz();
clazz.foo(); // Calling A.foo()

Multiple inheritance?

There is one common question that people ask about default methods when they hear about the new feature for the first time: “What if the class implements two interfaces and both those interfaces define a default method with the same signature?”. Let’s use the previous example to illustrate this situation:

public interface A {
    default void foo(){
       System.out.println("Calling A.foo()");
    }
}
 
public interface B {
    default void foo(){
       System.out.println("Calling B.foo()");
    }
}
 
public class Clazz implements A, B {
}

This code fails to compile with the following result:

java: class Clazz inherits unrelated defaults for foo() from types A and B

To fix that, in Clazz, we have to resolve it manually by overriding the conflicting method:

public class Clazz implements A, B {
    public void foo(){}
}

But what if we would like to call the default implementation of method foo() from interface A instead of implementing our own. It is possible to refer to refer to A#foo() as follows:

public class Clazz implements A, B {
    public void foo(){
       A.super.foo();
    }
}

Now I’m not quite sure that I like the final solution. Maybe it would be more elegant to specify the default method implementation in the signature, as it was specified in the first drafts of the default methods specification:

public class Clazz implements A, B {
    public void foo() default A.foo;
}

But it actually changes the grammar, doesn’t it? It looks more like a method declaration of an interface rather than the implementation form. But what if interface A and interface B define a lot of conflicting default methods and I’d like to resolve all the default methods from interface A? Currently, I’d have to resolve the conflicts one by one, overriding each conflicting method pair. That might be a lot of work and a lot of boilerplate code to write.

I guess there could be a lot of arguments for and against this way of resolving the conflicts but it seems that the creators just decided to accept the necessary evil.

Real examples

The real examples of the the default method implementations can be found in the early builds of JDK8. Going back to the example of forEach method for collections, we can find its default implementation in java.lang.Iterable interface:

@FunctionalInterface
public interface Iterable<T> {
    Iterator<T> iterator();
 
    default void forEach(Consumer<? super T> action) {
    	Objects.requireNonNull(action);
    	for (T t : this) {
        	action.accept(t);
    	}
    }
}

The forEach method takes java.util.function.Consumer functional interface type as a parameter which enables us to pass in a lambda or a method reference as follows:

List<?> list = …
list.forEach(System.out::println);

Method invocation

Let’s take a look on how the default methods are actually invoked. If you are not familiar with the subject, the Rebel Labs report on Java bytecode might be an interesting read for you.

From the client code perspective, default methods are just ordinary virtual methods. Hence the name – virtual extension methods. So in case of the simple example with one class that implements an interface with a default method, the client code that invokes the default method will generate invokeinterface at the call site.

A clazz = new Clazz();
clazz.foo(); // invokeinterface foo()
 
Clazz clazz = new Clazz();
clazz.foo(); // invokevirtual foo()

In case of the default methods conflict resolution, when we override the default method and would like to delegate the invocation to one of the interfaces the invokespecial is inferred as we would call the implementation specifically:

public class Clazz implements A, B {
    public void foo(){
       A.super.foo(); // invokespecial foo()
    }
}

Here’s the javap output:


public void foo();
Code:
0: aload_0
1: invokespecial #2 // InterfaceMethod A.foo:()V
4: return

As you can see, invokespecial instruction is used to invoke the interface method foo(). This is also something new from the bytecode point of view as previously you would only invoke methods via super that points to a class (parent class), and not to an interface.

Finally…

Default methods are an interesting addition to the Java language–you can think of them as a bridge between lambdas and JDK libraries. The primary goal of default methods is to enable an evolution of standard JDK interfaces and provide a smooth experience when we finally start using lambdas in Java 8. Who knows, maybe in the future we will see some more applications of default methods for API design.

In the meantime, stay tuned for more on Java 8 from Rebel Labs! Feel free to leave comments below or tweet us @RebelLabs.


Get the complete Rebel Labs report


  • Marc N

    Then if you could implement default methods in interfaces, wich will be then (in java 8) the differences between interfaces and abstract classes?
    Is this just a tweak to don’t break compatibility

  • arhan

    The difference will be minimal indeed. You can inherit only one abstract class, but you can implement multiple interfaces. Plus, you can’t declare mutable fields in interfaces, which you can do in abstract classes.

    Imo, this is an enabling feature. And yes, not to break the compatibility. However, this feature might be quite useful for API changes for any libraries in the future.

    Well, certainly it would be nice to see real extension methods in Java. But I guess this is not something what Java creators have in plans.

  • Marc N

    Thanks for the explanation.

  • Paul
  • Paul Duffin

    Default methods really only provide a one shot opportunity to add methods to an existing interface and then only for libraries provided with the JDK.

    Lets say that the forEach method is added to Collection. That won’t clash with other code that provides default methods as there will be no other code that can use default methods. However, once Java 8 is released then you cannot add any more default methods to Collection as they could clash with default methods provided by other interfaces. e.g. Say I have my own class that implements Collection and another interface OtherInterface. Before Java 8 is released the OtherInterface cannot contain any default methods so no possibility of clash, after Java 8 is released then OtherInterface could have its own default methods. When Java 9 is released it could not add additional default methods to Collection as they could clash with the default methods provided by my OtherInterface.

    The same issue applies for libraries that are not released as part of Java 8 because they do not know whether their default methods would clash with others.

  • Holger

    This is not a new problem. You can always have a method in a class which conflicts with an inherited method of a future version of its superclass. The JDK developers never stopped adding new methods to a class just because of potential conflicts with 3rd party subclasses. So it’s the same for interface default methods. There will be new methods if they are really useful.

    And to me it looks more like solving problems than creating new ones. I’m looking forward to a future with no more AbstractMethodErrors in JDBC due to interfaces newer than the existing drivers. Just one example…

  • Paul Duffin

    I am not saying it is not a good thing, I was just pointing out its limitations. It definitely does solve a problem, albeit not completely but probably as well as is possible. It changes what happens when adding methods to an interface from “will most likely break existing implementations” (it is not guaranteed as an existing implementation could already implement the added method itself) to “will most likely NOT break existing implementations”.

  • CriticalThinker

    I think if they’d just made multiple inheritance work this way with classes in the first place we wouldn’t need ‘interfaces’ to be something separate.

  • Brent Atkinson

    The problem you’re describing is one that is outlined in more detail. Draw your own conclusions. Personally, I think changing the collections classes to implement an extended interface would have been more appropriate:

    http://fmrldev.blogspot.com/2013/08/normal-0-false-false-false-en-us-x-none.html

  • Brent Atkinson

    “This is not a new problem. You can always have a method in a class which conflicts with an inherited method of a future version of its superclass.”

    You’re right, but it’s not the same. If the class Object was extended to have additional methods everyone’s classes would magically have them. However, the only conflict possible is easily resolved since a subclass can only have a single superclass. If the class already had a matching method, normal dispatch will select the more specific method. It might not be correct behaviorally, but structural integrity is maintained.

    “The JDK developers never stopped adding new methods to a class just because of potential conflicts with 3rd party subclasses.”

    Never? Being thoughtful about impacts of changes to existing and future code is a direct responsibility for API developers, even more so for language developers. They do this often and sometimes get it wrong.

    “And to me it looks more like solving problems than creating new ones.
    I’m looking forward to a future with no more AbstractMethodErrors in
    JDBC due to interfaces newer than the existing drivers.”

    Sorry, but this features adds new ways to get that error. See the results at http://fmrldev.blogspot.com/2013/08/normal-0-false-false-false-en-us-x-none.html

    Evolving interfaces is something to avoid in general. It is effectively silently changing a contract that someone has agreed to after they’ve signed it. Expecting them to honor it is not respecting reality. The frustrating bit is that an extended interface would have handled this just fine without introducing more potential reliability issues. It would have required implementing the new interface in collections, but it is a new interface in the abstract sense, it models the reality of the situation.

    Please do everyone a favor and don’t use this feature without an understanding of how damaging it can be to large systems. Treat it as what it is: a convenience to save Oracle’s Java team from having to add and implement an extended interface to the collections classes for lambda support.

  • An0nym0usC0ward

    Right. But it introduces yet another broken language feature, IMO (generics are my other huge disappointment – why can’t I have type safety at runtime?) It waters down the interface concept, which I liked very much – and which could have been enhanced in a different way, like providing actual contract-based programming in Java.

    By changing the VM to be able to wire a trait/mixin into a class at class loading time (and adding the mixin concept to the language) the platform could have been updated to solve the problem. A similar change could have been added to provide type safety for generic classes.

    This would have made the JVM into a more future-proof platform, and, as far as I understand the JVM, could have been added without breaking backwards compatibility. By adding kludges to the language Oracle just damages Java’s (the language’s) long-term prospects, IMO.

  • xx

    What is in the situation:

    interface A {
    default void m(){
    System.out.printl(“a”);
    }
    }

    interface B {
    default void m(){
    System.out.printl(“b”);
    }
    }

    class C {
    public void m(){
    System.out.printl(“c”);
    }
    }

    class D extends C implements A, B {
    //???
    }

  • bobbel

    If you are calling

    new D().m()

    you will get the output of C.m() because C is already overriding the default methods of both interfaces. It does not matter, if you want to implement the interfaces again explicitely. You have already overridden the methods of them.

  • Sandeep Sharma

    A very nice article. Precise and with some examples. I was confuse but now i think am more confortable with why default method has been introduced. I also see some examples at http://muhammadkhojaye.blogspot.com/2014/03/interface-default-methods-in-java-8.html how we can solve problems while implement more than one interface having same signature method.

  • saurav jain

    Whoa these days lots of buzz is going on default methods , once java 8 is officially release it i am sure that most of the applications will definitely going to use it.

    The reason why i think till now there was always a constraint that if we want to introduce some new method (prior to java 8) in an interface ,then it can break the whole application as all the implementation will be forced to provide an implementation for that ,so in that case we try to solve this problem by introducing a new interface to include that new method and i think here we violate the Single Responsibility Model (as its not stated anywhere).

    Again I personally feel that Abstract classes have their own cost of using them in terms of multiple inheritance and I also feel that Default methods and abstract classes have there own place in Java and they can’t replace each other.

    One more thing I found an interesting interesting article on Default methods here , it is little bit on the sarcastic side but a worth reading.

    http://lotusmediacentre.com/default-methods-in-java-8-explained/

  • Shan

    Many of they are still stand with java 1.5 & 1.6 .Going forward the migration happens directly to java 8 .