19

I'm taking a look to Java 8 news compared to 7 and in addition to very interesting things like lambdas or the new time framework, i found that a new feature(?) was introduced: default methods.

I found the following example in this article:

public interface Math {

    int add(int a, int b);

    default int multiply(int a, int b) {
        return a * b;
    }
}

It seems very strange to me. Above code looks like an abstract class with an implemented method. So, why to introduce default methods in an interface? What is the actual advantage of this approach?

In the same article I read this explaination:

Why would one want to add methods into Interfaces? We’ll it is because interfaces are too tightly coupled with their implementation classes. i.e. it is not possible to add a method in interface without breaking the implementor class. Once you add a method in interface, all its implemented classes must declare method body of this new method.

Well this doesn't convince me at all. IMHO I believe that when a class implements an interface obviosly must declare methods body for each method in it. This is surely a constraint, but it's also a confirm of its "nature" (if you understand what I mean...)

If you have common logic to every inheriting class you'll put it into an implementing abstract class.

So, what's the real advantage of a default method? (It looks more like a workaround than a new feature...)


UPDATE I understand that this approach is for backwards compatibility, but it still doesn't convince me so much. An interface represent a behaviour that a class MUST have. So a class implementing a certain interface has surely this behaviour. But if someone can arbitrarily change the interface, this constraint is broken. The behaviour can change anytime... Am I wrong?

davioooh
  • 23,742
  • 39
  • 159
  • 250
  • Related: http://stackoverflow.com/questions/19998454/interface-with-default-methods-vs-abstract-class-in-java-8 and http://stackoverflow.com/questions/20139404/java-8-default-methods-vs-non-abstract-methods-in-abstract-classes – assylias Sep 11 '14 at 09:59
  • 1
    You can `extend` only one class, but `implement` as many interfaces as you want. – Florent Bayle Sep 11 '14 at 09:59

3 Answers3

18

This is for backwards compatibility.

If you have an interface that other people have implemented then if you add a new method to the interface all existing implementations are broken.

By adding a new method with a default implementation you remaining source-compatible with existing implementations.

For a slightly simple/contrived example that should hopefully demonstrate this let us say you created a library:

void drawSomething(Thing thing) {
}

interface Thing {
    Color getColor();
    Image getBackgroundImage();
}

Now you come to do a new version of your library and you want to add the concept of border colors, that's easy to add to the interface:

interface Thing {
    Color getColor();
    Color getBorderColor();
    Image getBackgroundImage();
}

But the problem is that every single person using your library has to go back through every single Skin implementation they ever did and add this new method.

If instead you provided a default implementation to getBorderColor that just called getColor then everything "just works".

Tim B
  • 40,716
  • 16
  • 83
  • 128
  • 1
    ok, but adding method body within an interface sounds very strange to me... – davioooh Sep 11 '14 at 10:01
  • 2
    @davioooh it is strange, but when Oracle were faced with breaking backwards compatibility in Java 8 when adding lambda enhanced methods to the collections apis; they chose this approach as the lesser evil. – Chris K Sep 11 '14 at 10:02
  • Even then,this backward compatibility holds only for one method, what in case we have to introduce another method? – ajay.patel Sep 11 '14 at 10:03
  • @zerocool Just provide default implementations for every new method – Tim B Sep 11 '14 at 10:04
  • @davioooh I've added an example to help. – Tim B Sep 11 '14 at 10:04
  • @TimB got it, so there can be n number of methods which have default implementation? – ajay.patel Sep 11 '14 at 10:06
  • 2
    @zerocool Yep, as many as you like. Most interfaces have none, some have 1 or 2, in theory one could have a lot although that's most likely a sign of something wrong in your architecture. – Tim B Sep 11 '14 at 10:08
  • @TimB I understand, but this approach doesn't convince me so much. An interface represent a behaviour that a class MUST have. A class implementing a certain interface has surely this behaviour. But if someone can arbitrarily change the interface, this constraint is broken. The behaviour can change in every moment... Am I wrong? – davioooh Sep 11 '14 at 10:09
  • 1
    @davioooh In an ideal world it would never happen. However we don't program in an ideal world. Sometimes you need to add more functionality to an existing interface and this allows you to do that without breaking existing users of an interface. It's a tool to mitigate the impact of changes to a libraries API on users of that library. – Tim B Sep 11 '14 at 10:13
  • @TimB ok, understood. but I don't like it... :) thank you! – davioooh Sep 11 '14 at 10:22
6

There have been a lot of methods acting on an abstract interface in the past. Before Java 8 they had to be put into an additional class pairing the interface, e.g. Collections with Collection.

This old approach was neither more convincing than default methods nor more practical. Instead of list.sort() you had to say Collections.sort(list). This also implies that you had to make a fundamental decision when creating an interface, either you require every List implementation to implement a sort method or you provide a sort method in a utility class that cannot be overridden.

With default methods you can have both, a standard implementation which the List implementations do not need to implement on its own but still can be overridden if a concrete implementation has a more efficient way to do it knowing its internals, e.g. ArrayList.sort passes its internal array directly to Arrays.sort skipping some intermediate operations.

Holger
  • 285,553
  • 42
  • 434
  • 765
4

Suppose at some point you want to add new functionality in declared interface, up to Java 7, If you will add a new method in declared an interface, you also have to define the implementation of the method in classes that are implementing that interface.

In java 8, You can add a default method containing the implementation and all the child class will inherit that method.

Edit : (After question update)

An interface represent a behaviour that a class MUST have

It still represent a behaviour that class must have, your confusion is how you are defining behaviour. All implementing class will inherit default method and are also free to write their own implementation. consider following two cases,

  1. If implementing class does not provide own implementation and simply inherit default method. If you change behaviour of default method in interface, implementing classes will be having updated behaviour as they inherit default method so it holds An interface represent a behaviour that a class MUST have.
  2. If implementing class provide own version of default method, and if you will change behaviour (only arguments) of default method. In this case implementing class will be having two overloaded methods, one which was earlier defined and second one is inherited default method. and if you change complete behaviour (arguments with return type also), It will create ambiguity in implementing class as you can not overload method by changing return type and Implementation will be broken. again it holds An interface represent a behaviour that a class MUST have.

Example :

Bulk data operation in collection is added in Java 8 (Reference : http://openjdk.java.net/jeps/107), to implement that forEach() method is added in Iterable interface. Adding abstract method in Iterable interface would break all the existing code because each class has to implement that method.

Solving the issue, following default forEach() method is added in Iterable interface,

interface Iterable 
{ 
   default void forEach(Consumer<? super T> action) 
   { 
      for (T t : this) action.accept(t); 
   } 
}

Reference : Java 8 : Default method in Interface

Not a bug
  • 4,286
  • 2
  • 40
  • 80
  • Your reference is a bit outdated. What was called `Block` in very early versions has been named `Consumer` for quite a while now. Further, it makes no sense telling (correctly) that `forEach` has been added to `Iterable` but write example code defining it in `Collection` right afterwards. See http://docs.oracle.com/javase/8/docs/api/java/lang/Iterable.html#forEach-java.util.function.Consumer- – Holger Sep 11 '14 at 10:56
  • @Holger I am not getting you point about `forEach`, can you please explain lil bit !! (not arguing, take this as a positive pls) – Not a bug Sep 11 '14 at 11:01
  • @Holger Ohh !!! updated the answer, and will update article too. It was written long while ago (31st March 2014), btw thanks :) – Not a bug Sep 11 '14 at 12:09