Monday, July 28, 2014

Default, Defender or Extension Method of Java 8 with Example

Java 8 now allows you to add non-abstract method implementations to interfaces by utilizing the default and static keyword. Methods with default keyword are known as default methods or defender methods in Java. Before Java 8, it was virtually impossible to change an interface once published. Any change e.g. addition of a new method would have broken all clients. That's why when Java 8 decided to switch to internal iterator implementation using forEach() method, they face a daunting challenge of breaking all implementation of Iterable interface. Since backward compatibility is top priority for Java engineers, and it wasn't practical to break all clients, they came up with idea of default method. This is an amazing and very powerful change, because now you can evolve your existing interface with all the knowledge you have gained after using them. JDK itself is utilizing default methods in big way, java.util.Map interface is extended with several new default methods e.g. replaceAll(), putIfAbsent(Key k, Value v) and others. By the way, Since default method allows extension of existing interface, it’s also known as Extension method. You are also free to define any number of default method in your interface. I think after this change, you unlikely need an abstract class to provide skeletal implementation as described in Effective Java e.g. List comes with AbstractList, Collection comes with AbstractCollection, Set comes with AbstractSet and Map comes with AbstractMap. Instead of creating a new abstract class with default implementation, you can define them as default method inside interface itself. Similarly, introduction of static methods inside interface will make pattern of an interface utility class redundant e.g. Collections for Collection interface, Paths for Path and so on. You can directly define static utility method on interface itself.

 

Java 8 Example of Default Methods

Java 8 enables us to add non-abstract method implementations to interfaces by utilizing the default keyword. This feature is also known as Extension Methods. Here is our first example:

interface Multiplication{
    int multiply(int a, int b);
   
    default int square(int a){
        return multiply(a, a);
    }
}

Besides the abstract method multiply() the interface Multiplication also defines the default method square(). Any concrete classes of Multiplication interface only have to implement the abstract method multiply(). The default method square() method can be used directly.

  Multiplication product = new Multiplication(){
           
      @Override
      public int multiply(int x, int y){
          return x*y;
      }
  };
       
  int square = product.square(2);
  int multiplication = product.multiply(2, 3);

The product sub class is implemented using an anonymous class. The code is quite verbose : 6 lines of code for such a simple multiplication. You can reduce a lot of boiler plate code by using lambda expression, which is also introduced on Java 8. Since our interface contains only one abstract method and Java's lambda expression is of SAM type (Single Abstract method), we can replace anonymous class implementation with just one line of lambda expression, as shown below :

Multiplication lambda = (x, y) -> x*y;
 
int product = lambda.multiply(3, 4);
int square = lambda.square(4);

Here is our complete Java program to demonstrate how you can use default methods inside interface in Java 8. As I said, now, you can even extend your old interface to add new methods without any fear of breaking clients, provided those methods must be either default or static.


/**
* Java Program to demonstrate use of default method in Java 8.
 * You can define non-abstract method by using default keyword, and more
 * than one default method is permitted, which allows you to ship default skeletal
* implementation on interface itself.
*
* @author Javin Paul
*/
public class Java8DefaultMethodDemo{
 
    public static void main(String args[]) {
 
        // Implementing interface using Anonymous class
        Multiplication product = new Multiplication(){
           
            @Override
            public int multiply(int x, int y){
                return x*y;
            }
        };
       
        int squareOfTwo = product.square(2);
        int cubeOfTwo = product.cube(2);
 
        System.out.println("Square of Two : " + squareOfTwo);
        System.out.println("Cube of Two : " + cubeOfTwo);
       
        // Since Multiplication has only one abstract method, it can
        // also be implemented using lambda expression in Java 8
       
        Multiplication lambda = (x, y) -> x*y;
       
        int squareOfThree = lambda.square(3);
        int cubeOfThree = lambda.cube(3);
       
        System.out.println("Square of Three : " + squareOfThree);
        System.out.println("Cube of Three : " + cubeOfThree);
       
    }
 
}
 
interface Multiplication{
    int multiply(int a, int b);
   
    default int square(int a){
        return multiply(a, a);
    }
   
    default int cube(int a){
        return multiply(multiply(a, a), a);
    }
}
Output :
Square of Two : 4
Cube of Two : 8
Square of Three : 9
Cube of Three : 27

This code is an excellent example of how you can use default methods to add convenient methods on interface itself. This is also an example of template method pattern and avoids an extra helper class e.g. Collections, which just provide utility method to work on Collection. You can now define such methods in the Collection class itself. In this example of Java 8 default method, we have an interface Multiplication, which has its core abstract method called multiply(a, b), which supposed to multiply two numbers. It has then create two concrete method using default keyword, called square(a) and cube(a), which depends upon multiply(a, b) method for their function. Now, client just need to implement multiply() method, and he will get both square(a) and cube(a) for free.


Important points about Java 8 Default Methods

Default and Defender Method of Java 8 with Example
Now it's time to revise whatever we have learned so far and note down some of the important things about our new defender, extension or default method of Java 8. You can take away all the knowledge in form of these bullet points. It's not only help you to quickly revise the topic but also encourage you to explore further and discover more about those individual things.

1) You can add default methods either on new interface or existing methods, provided they are compiled using source version of Java 8.

2) Default methods has blurred difference between abstract class and interface in Java. So next time while answering this question on interview, don't forget to mention that you can do some of the things which was only possible with abstract class using default keyword. You can now define concrete methods on interfaces with the help of default methods.

3) default is not a new keyword, instead it was reserved form JDK 1.1 for these kind of evolution.

4) You are free to define any number of default methods in your interface. There is no restriction on number of default method an interface can contain in Java 8.

5) If an interface let's say C, extend two interfaces A and B, which has default method with same name and signature then compiler will complain about this while compiling class C. It's not allowed in Java 8 to avoid ambiguity. So even after default methods, multiple inheritance is still not allowed in Java 8. You cannot extend multiple interface with conflicting Java interface default method implementation.

6) There are lot of examples of Java 8 interface default methods are available in JDK 1.8 code base, one of the most popular one is forEach() method. You can also open interfaces like java.util.Map to see new default methods e.g. putIfAbsent(), which was only available to ConcurrentMap prior to JDK 1.8 version.


That's all about default methods of Java 8. This is one of the breakthrough change, which will open path for better and more convenient interfaces. Best way to remember default method is to remember problem of using putIfAbsent() method of ConcurrentMap from JDK 1.7, which was not present in Map. It was not possible to write methods which can directly operate on Map interface because any time if a Map interface points to a ConcurrentMap object, you need to cast into ConcurrentMap just for sake of using putIfAbsent() method. With extension methods, now JDK 8's java.util.Map interface has got its own putIfAbsent() method.

4 comments :

Sandeep said...

Can we assume that this feature is going to replace Abstract classes?

Anonymous said...

I don't think so because Abstract class is more capable than interface even with default methods e.g. you can not define instance variables inside interface. Default methods are best utilized to enhance existing interfaces with the knowledge acquired after their usage, as JDK has done with java.util.Map interface.

janakan kanaganayagam said...

Exactly what I Sandeep... But due to backward compatibility the abstract classes would remain I presume

Anonymous said...

Does default methods has any performance penalty over instance method, static or final method?

Post a Comment