DEV Community

Cover image for Default and private methods in Interfaces
Dan Newton
Dan Newton

Posted on • Originally published at lankydan.dev on

Default and private methods in Interfaces

In this tutorial, we will look at default and private methods within interfaces. Default methods were added in Java 8 allowing methods to be added to an interface that comes with a default implementation that could be used, overridden or ignored without causing issues to existing classes that have implemented an interface. Private methods were missing when default methods were added, preventing code being split out into smaller methods within an interface. This is something that was a bit off-putting to me as if you had a default method that became a bit long there was no way to tidy it up. So now that both default and private methods can exist within an interface we can write methods like we are used to, although if you haven’t used default methods yet then you will first need to get past the fact that there is now actual code living in an interface.

In terms of adding default and private methods to an interface, its really simple. To add a default method just add the keyword default to the method definition and I’m not even going to tell you how to add a private method as I don’t wish to insult you!

Being it’s so simple lets just jump straight into some code examples.

public interface MyInterface {

  default void defaultMethod() {
    privateMethod("Hello from the default method!");
  }

  private void privateMethod(final String string) {
    System.out.println(string);
  }

  void normalMethod();
}

public class MyClassWithDefaultMethod implements MyInterface {

  @Override
  public void normalMethod() {
    System.out.println("Hello from the implemented method!");
  }
}
Enter fullscreen mode Exit fullscreen mode

As you can see from the basic snippets above a default method is defined on the interface which in turn calls a private method. As the name suggests it is a default method and therefore due to MyClassWithDefaultMethod not providing an implementation for defaultMethod it will carry on and use what is defined on the interface. So if defaultMethod and normalMethod were called they would produce the following output.

Hello from the default method!
Hello from the implemented method!
Enter fullscreen mode Exit fullscreen mode

There is really not much to it. If you wanted to provide your own implementation of the default method within the class then as you would with a normal interface method, just add a method with the same name and preferably pop the @Override annotation on top of it.

public class MyClassOverrideDefaultMethod implements MyInterface {

  @Override
  public void normalMethod() {
    System.out.println("Hello from the implemented method!");
  }

  @Override
  public void defaultMethod() {
    System.out.println("I have overridden the default method!!");
  }
}
Enter fullscreen mode Exit fullscreen mode

Nothing really to say about this code as now it looks like a normal class that has implemented an interface. When run it will produce the following output rather than what was shown previously.

I have overridden the default method!!
Hello from the implemented method!
Enter fullscreen mode Exit fullscreen mode

That's the basics of adding default and private methods to interfaces. Below we will look a bit more in-depth into default methods as well as why to use them in the first place.

So a class can have multiple interfaces and now an interface can define it’s own default methods. What happens if a class implements multiple interfaces which each have the same default method defined? Well, not much happens really as it will fail to compile and produce the following error.

java: class MyClassWithTwoInterfaces inherits unrelated defaults for defaultMethod() 
from types MyInterface and MyOtherInterface
Enter fullscreen mode Exit fullscreen mode

As you can probably figure out, it cannot determine which default method it should actually use so it blows up. To get around this situation we need need to provide an implementation that will override the versions that the interfaces are giving the class which will be used instead and thus removing the ambiguity which resulted in the error.

Moving onto the next point. A class can override a default interface method and call the original method by using super, keeping it nicely in line with calling a super method from an extended class. But there is one catch, you need to put the name of the interface before calling super this is necessary even if only one interface is added. This makes sense as super normally refers to the extended class and as multiple interfaces are allowed restricting it to always being called like this keeps it consistent and without any ambiguity. Below is a code snippet of what this would look like.

public class MyClassWithTwoInterfaces implements MyInterface, MyOtherInterface {

  @Override
  public void normalMethod() {
    // some implementation
  }

  @Override
  public void defaultMethod() {
    MyInterface.super.defaultMethod();
    MyOtherInterface.super.defaultMethod();
  }
}
Enter fullscreen mode Exit fullscreen mode

Being able to call super on a default interface method also resolves the error the same default method from multiple interfaces. You will still need to override the method itself but you don't need to write much more than that, if one of the original versions satisfies your needs you can call super on the implementation you desire and be done with it.

As an interface can extend another interface what happens when both contain a default method of the same name? I’m sure most of you can figure out the answer, but in case you can’t it simply takes the implementation from the child interface / the interface furthest down the hierarchy tree.

public interface MyInterface {

  default void defaultMethod() {
    System.out.println("Hello from the parent interface!");
  }
}

public interface MyOtherInterface extends MyInterface {

  default void defaultMethod() {
    System.out.println("Hello from the child interface!");
  }
}
Enter fullscreen mode Exit fullscreen mode

When a class implements MyOtherInterface and calls defaultMethod it will print out.

Hello from the child interface!
Enter fullscreen mode Exit fullscreen mode

As you can see it has called defaultMethod from within the child interface MyOtherInterface. This keeps it in line with providing an implementation to a default method from within a class, if it is included in the child/implementation then it will use that instead of the original defined on the parent interface.

So why use default methods in the first place? After doing some googling, it seems that they were added to Java 8 as a way of adding methods in preparation for Lambda expressions without breaking code that implemented existing interfaces. So if we had a class that used an interface that was changed, for example, code within a 3rd party library, we wouldn’t need to worry about any new methods being added to the interface as our existing code will still work and the new method can be ignored until a later date. By using this example I believe it is more important for API / library developers to consider using default methods than it is for those that are writing code within their own codebase where they are in control of everything and can change any classes that have been broken by adding a new interface method.

Below are some code snippets to help make the above point clearer (if it wasn’t already).

public class MyClass implements MyOldInterface {

  @Override
  public void doStuff() {
    // does stuff
  }
}

public interface MyOldInterface {

  void doStuff();
}
Enter fullscreen mode Exit fullscreen mode

So here we have a class that is sitting around nice and happy as it has implemented the method defined on the interface and requires no other work to be done. And then we come along without a care in the world and add a new method to the interface.

public interface MyNewInterface {

  void doStuff();

  void doSomeMore();
}
Enter fullscreen mode Exit fullscreen mode

When we try to compile the code it will fail as we have not provided an implementation for doSomeMore. Obviously this makes us cry as we need to write some extra code, even if it is some half-arsed code just so we can get it to work again. Whereas if the code before was written instead…

public interface MyNewInterface {

  void doStuff();

  default void doSomeMore() {
    // do some more stuff
  }
}
Enter fullscreen mode Exit fullscreen mode

We would remain happy as our existing class requireS no extra work and will still compile. When we eventually decide that we need to implement the new method added to the interface then we can do so as normal. Furthermore, if the doSomeMore method was long enough maybe a private method or two could be used to keep the interface nice and tidy, helping you keep everyone who uses your code happy!

I think that pretty much covers it. In conclusion default methods were added as part of Java 8 with private methods being an addition in Java 9. Default methods allow an interface to define an implementation for a method so that when a class implements the interface it does not need to provide it’s own version of the method, helping APIs and libraries move forward without always needing to make breaking changes when interfaces require additional methods. Hopefully, this post demonstrated their ease of use, although just because they are simple does not mean they should be added all over the place and developers only concerned about their own codebase might never find a need to use them. I almost forgot to mention private methods here, but quite frankly that’s because there's not much to say about them and if you noticed while going through this post there is barely any mention of them. Private methods in interfaces are there to make code look nicer and give the option of some code reuse.

If you found this post helpful, please share it and if you want to keep up with my latest posts then you can follow me on Twitter at @LankyDanDev.

Top comments (2)

Collapse
 
ramprogrammer profile image
Hanuma

thank you so much. dont know how many years it would have taken to find out why default methods were actually added. I was thinking does default methods have any contribution to object oriented design? seems No. They are just for backward compatiability.

Collapse
 
ramprogrammer profile image
Hanuma

If one can further reason why default are overridden, we can answer it why from the above post.