What is Default or Defender Methods of Java 8 - Tutorial Example

Whenever someone talks about Java 8, the first thing they speak about is lambda expression and how lambda expression has changed the way you use Collections API today. In truth, lambda expression would not be that useful had language not been enhanced to support default methods on Java Interface. Also known as a virtual extension or defender methods, they allow you to declare a non-abstract method inside Java interface. Which means, finally you can add new methods without breaking all classes, which implements a certain interface. This opens a new path for enhancing and evolving existing Collection API to take advantage of lambda expressions. For example, now you can iterate over all elements of Collection in just one line, as opposed to four lines it requires you to do prior to Java 8.

The forEach is a default method declared inside java.lang.Iterable, which allows Java to iterate over collection internally and execute action asked by the client. Since now iteration is internally handled by Java, they can do a lot of things which were not possible earlier like parallel iteration.

Parallel libraries are long been due on the Java platform to leverage the immense power of multiple CPUs available to modern servers. Since handling parallelism on the client side is both difficult and error prone, programmers have been asking for libraries, which can do things in parallel, leaving you to only define what to do, instead of how to do.

Bulk data operation, like applying logic on each or some elements of a Collection was possible because of default methods like forEach.

In this article, we will learn what is default method, will see few examples of default method on the custom interface and from JDK itself, understand how differences between abstract class and the interface in Java 8 are reduced due to the introduction of defender methods and finally answer some frequently asked questions on Java 8 default methods. So fasten your seat belt and be ready for a short ride on Java 8 default methods.

Btw, if you are new to Java or Java 8 world then I suggest you to first join a comprehensive course like The Complete Java MasterClass instead of learning in bits and pieces. The course provides a more structured learning material which will teach you all Java fundamentals in quick time. Once you understand them you can explore the topic you like by following blog posts and articles.




What is Default or Defender Methods of Java 8

Default methods, also known as virtual extension methods or defender methods is a non-abstract method, which can be declared inside an interface in Java. If you have been using interface in Java then you know that it’s not possible to change the structure of the interface, without breaking its implementations, once it's published.

This means you cannot add new methods on the existing interface like java.util.Map or java.util.List which is used heavily in almost all Java programs.

This was a serious limitation and was affecting the fluent use of lambda expression with Collections API. Since one of the common use cases of a lambda expression is to apply some operation to each element of Collection, it is not possible until you have a method, which allows you to iterate over List.

For example, adding a method like forEach() inside java.util.List would have broken all List implementation exists in Java world, and that's why the idea of default method was introduced.

This way, you can declare a concrete method inside an interface without breaking its clients. Since introducing this means, an interface is no more completely abstract, a few rules in the compiler is needed to ensure that it wouldn't create the diamond problem, one of the reasons Java doesn't support multiple inheritances.

Reserve keyword default is used to make a method default inside interface, it’s not mandatory for an implementer to override Java 8 default methods, but it can if it wish to.

Also, no special bytecode instruction is provided for calling default methods, It will make use of existing invokeinterface, invokevirtual, and invokespecial bytecode method instructions.

If you want to learn more about Java 8 features like lambda expression, Stream API, and new Date and Time API, then What's New in Java 8 course on Pluralsight is a good starting point to quickly become familiar with these essential Java 8 features.

What is Default or Defender Methods of Java 8 - Tutorial Example



Why Default Methods was Introduced in Java 8

The lambda expression in Java is of SAM type, which means a type of Single abstract method, interface like Comparable, Comparator and Runnable fits this bill and were an obvious candidate to be used in a lambda expression, but another use case of using lambdas is allowing to operate them over each element of Collection.

Since so far collection doesn't know how to iterate over themselves, adding a method like forEach() on Collection or List interface would have broken all existing implementation, so they thought about a Virtual extension or defender methods. Which means you can finally declare a non-abstract method inside interface, without breaking its client.

Had they introduced Java 8 lambda expression without default method like forEach() on java.lang.Iterable, It wouldn't help in the development of parallel libraries, which is the core intention of introducing lambda expression to exploit the capability of multiple CPUs available in modern computers.

So in a sense, the default method was critical to support the development of bulk data operations with a lambda expression. If you want to learn more about bulk data operation and Stream API, I suggest you go through Java Streams API Developer Guide on Udemy, one of the hands-on course to learn and master Stream API of Java 8.

what is the purpose of default method in Java



Default Method Example in Java 8

Here is a simple example of an interface, which has implemented Java 8 default methods. You need to download JDK 8 to run this program.

There are a lot of interesting things to note about this example, first of all, did you notice that class TextParser neither implements parse() method not declared as abstract, but it still compiles fine. This is possible because parse() is a default method, had Parser contains another method, which was not a defender method, TextParser either has to override that method or declare itself as abstract.

Next interesting thing is what happens if parse() method is called with an instance of TextParser class? Well, it will call default implementation provided in the interface itself. Next is our class XMLParser, which does override parse(), which means it’s possible to override default methods in Java.

Now if you invoke the default method with an instance of subclass e.g. XMLParser, it will invoke the overridden method, as shown in the output.

interface Parser{   
    default void parse(){
        System.out.println("default Parsing logic");
    }
}

class TextParser implements Parser{ 
    // No compile time error, because parse is default method
    //inherit default implementation of parse
}

public class XMLParser implements Parser{
   
    @Override
    public void parse(){
        System.out.println("Parsing XML files");
    }
   
    public static void main(String args[]){
        Parser p = new TextParser();
        p.parse();
       
        p = new XMLParser();
        p.parse();
    }
}

Output:
default Parsing logic
Parsing XML files


Let's take another real example of default methods, which is probably the most popular one, which connects default methods to lambda expressions. The forEach method is defined as a default method inside java.lang.Iterable class as shown below :

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

Since List implements Collection interface, which in turn implements Iterable, this allows you to write following kind of code, which operates on each element.  This code print each element from a list :

List<Integer> numbers = Arrays.asList(1,2,3,4,5,6);
numbers.forEach(System.out::println);

The forEach() is just an example. The JDK designers have added several useful methods in existing interfaces e.g. sort() in List and removeIf() in Collection. There are a couple in the Map interface as well. You should check a good Java book like Java 8 in Action to find out more about such important methods.
Java 8 Default Methods On Interface


That's all about what is default methods in Java 8, Why default or defender methods were added in Java programming language and how default methods works. Though they are instrumental in the evolution of lambda expression and Collections API in Java 8, they are not something, which should be used every day.

Treat your interface as pure interface and only add default methods, if it becomes really necessary, keep it as your last option, not the first one, similar to how they have been used in Java 8. Remember Java 8 is not supporting multiple inheritances of classes, and even with default method, the compiler will ensure it won't cause ambiguity to avoid the diamond problem.

To take full advantage of lambda expression and default methods, take a look at Java 8 API docs to see which interfaces are enhanced with default methods and How you can use them with a lambda expression.

Further Learning
The Complete Java MasterClass
Java 8 New Features in Simple Way
From Collections to Streams in Java 8


Related Java 8 Tutorials
If you are interested in learning more about new features of Java 8, here are my earlier articles covering some of the important concepts of Java 8:
  • 5 Books to Learn Java 8 from Scratch (books)
  • 5 Free Courses to Learn Java 8 and beyond (courses)
  • How to join String in Java 8 (example)
  • How to use filter() method in Java 8 (tutorial)
  • How to format/parse the date with LocalDateTime in Java 8? (tutorial)
  • How to use Stream class in Java 8 (tutorial)
  • How to convert List to Map in Java 8 (solution)
  • 20 Examples of Date and Time in Java 8 (tutorial)
  • How to use peek() method in Java 8 (example)
  • How to sort the map by keys in Java 8? (example)
  • How to sort the may by values in Java 8? (example)
  • 10 examples of Optional in Java 8? (example)
  • 10 Free Courses to Master Java Programming (courses)
Thanks for reading this article so far. If you like this article then please share with your friends and colleagues. If you have any question or feedback then please drop a comment.

P. S. - If you are interested in learning more about Java 8 features like lambda expression, Stream API, and new Date and Time API, then What's New in Java 8 course on Pluralsight is a good starting point to quickly become familiar with these features.

6 comments:

  1. Good content. It could be improved by adding on how Java8 provides solution to "diamond problem". i.e. FileParser.super.parse() example

    ReplyDelete
    Replies
    1. Yes, there are some rules to resolve conflict if same method is inherited from two super interfaces. I don't remember that on top of my head but you can find about that on Java specification.

      Delete
  2. What is the difference between adding concrete methods in abstract class and adding default methods in interface?

    ReplyDelete
    Replies
    1. This is a good question and answer lies on the fact that what you can do, it like adding a new method on a class or interface. If you have interface at the top of hierarchy then default method is only option.

      Delete
  3. This para is not clear. Can you explain this -
    Had they introduced Java 8 lambda expression *without* default method like forEach() on java.lang.Iterable, It *wouldn't* help in the development of parallel libraries, which is the core intention of introducing lambda expression to exploit the capability of multiple CPUs available in modern computers.

    ReplyDelete
    Replies
    1. Hello @Anonymous, concept of default method allows you to add concrete methods on interface, it wasn't possible before Java 8. This pave the road for interface evolution, one example of that is forEach() method which was added on Iterable. If you didn't have default method then there won't be any new methods on interface, which means lambda expression would have been limited only to new interfaces. This was not the goal because it wouldn't help much as 90% coding in Java would have used those old classes like Map, Iterable etc

      Delete