Java 8 New Feature: Default and Static Methods

Koushik Saha's Avatar author of Java 8 New Feature: Default and Static Methods
Java 8s Default and Static methods in interfaces reduces burden of modifying the implementation classes when new functionality is added to the interface..
Java 8 is the major release after the release of Java 5 that significantly improved the Java language. It has introduced many cool new features. One of them is the Default and Static methods in interfaces. This feature has reduced the burden of modifying the implementation classes of existing interface when new functionality is added to the interface.

As defined in the Java language, an interface is a contract that specifies what functionalities are available to the outside world. The implementers use this contract to define the functionalities. In other words, an interface is a reference type and contains constant fields, method signatures, and nested types. These interfaces cannot be instantiated. This means that either they can be implemented by concrete classes or extended by other interfaces. Since Java 8, interfaces can now contain default methods and static methods.

Default Methods



Consider a case where an interface contains a few method signatures. The implementers have implemented all these methods in their implementation classes to adhere to the contract (interface). Now, a new method signature has to be added to the interface. This will need all the implementers to modify their implementation classes to add the definition of the newly added method as all the methods in an interface must be implemented. Prior to Java 8, there were two options:
  • Create a new interface that extends the existing interface and add the new method. This will make the users aware that they can use either the new interface to use the new method or the old interface to stick to their previous implementation. But this will increase the number of interfaces and reduce maintainability.
  • Change the interface to an abstract class and add new concrete method with default implementation so that the implementers need not require to create the implementation of the new method. But this will prevent the implementation classes to extend other classes.
Default methods (alternatively known as Defender methods) have been introduced to overcome this problem. A default method is a method defined in the interface that has its implementation. The signature of the default method starts with default keyword. Every implementation class that implements this interface inherits this default method and can override them as well reducing the burden of modifying the existing code and binaries. They are public in nature as like any other interface method.
Code:
package example;
public interface Person {

    String getFirstName();
    String getLastName();
    
    // default method in interface
    default String getFullName() {
   	 return getFirstName() + " " + getLastName();
    }
}

package example;
public class Employee implements Person {

    private String firstName;
    private String lastName;
    
    public Employee(String firstName, String lastName) {
   	 this.firstName = firstName;
   	 this.lastName = lastName;
    }
    
    @Override
    public String getFirstName() {
   	 return this.firstName;
    }

    @Override
    public String getLastName() {
   	 return this.lastName;
    }    
}

package example;
public class Contractor implements Person {

    private String firstName;
    private String lastName;
    
    public Contractor(String firstName, String lastName) {
   	 this.firstName = firstName;
   	 this.lastName = lastName;
    }
    
    @Override
    public String getFirstName() {
   	 return this.firstName;
    }

    @Override
    public String getLastName() {
   	 return this.lastName;
    }

    //This class overrides the default method of interface
    @Override
    public String getFullName() {
       return getLastName() + ", " + getFirstName();
    }
}

package example;
public class DefaultMethodExample {
    public static void main(String args[]) {
   	 Person employee = new Employee("John", "Smith");
   	 Person contractor = new Contractor("Mark", "Brown");
   	 System.out.println("Full Name: " + employee.getFullName());
   	 System.out.println("Full Name: " + contractor.getFullName());
    }
}
In the above example, Person in an interface that has three methods, two abstract method getFirstName() and getLastName() and a default method getFullName(). All implementation classes Employee and Contractor implement the getFirstName() and getLastName() but only Contractor class implements getFullName(). This means Employee class do not require to implement the default method of the interface and will inherit the implementation of the default method from Person interface automatically. Do also note that the default method can be made abstract by child interfaces or abstract classes to enforce concrete implementation by its subclasses.

The output of the above code is shown below:



Restrictions of default methods:

  • The default method cannot be final, so as to prevent modifying the default implementation of the method in the inherited classes.
  • The default method cannot be synchronized, while the synchronized block can be added inside the default method as mentioned in code below:
    Code:
    package example;
    public interface Person {
    
        String getFirstName();
        String getLastName();
        
        // synchronized keyword in default method not allowed
        default synchronized int saveInDB() {
          System.out.println("Update DB");
       	 return 1;
        }
    
        // synchronized block in default method is allowed
        default int saveInDB() {
          synchronized(this) {
            System.out.println("Update DB");
          }
       	 return 1;
        }
    }
  • The default method cannot be used to override any method of java.lang.Object class that is not final.This is because it is irrelevant to create a default method same as a non final method of Object class as all classes inherit the Object class and can cause confusion about its actual implementation in the sub classes.
  • In case of multiple inheritance, implementing two or more interfaces having default methods with same method signature is not allowed. In that case, the implementation class must override the default method implementation to use the definition of any one interface or provide its own implementation. See the below code:
    Code:
    package example;
    public interface Book {
    
        String getTitle();
        String getAuthor();
        
        default void display() {
       	 System.out.println("Book: " + getTitle());
        }
    }
    
    package example;
    public interface Publisher {
    
        String getName();
        String getAddress();
        
        default void display() {
       	 System.out.println("Publisher: " + getName());
        }
    }
    
    package example;
    public class BookDetails implements Book, Publisher {
    
        private String name;
        private String address;
        private String title;
        private String author;
        
        public BookDetails(String aName, String aAddress, 
                      String aTitle, String aAuthor) {
       	 name = aName;
       	 address = aAddress;
       	 title = aTitle;
       	 author = aAuthor;
        }
        
        @Override
        public String getName() {
       	 return name;
        }
    
        @Override
        public String getAddress() {
       	 return address;
        }
    
        @Override
        public String getTitle() {
       	 return title;
        }
    
        @Override
        public String getAuthor() {
       	 return author;
        }
    
        // Need to override the display method, otherwise 
        // it would throw Compilation error
        @Override
        public void display() {
       	 // Inherit the default implementation of Book interface
       	 Book.super.display();
        }
    }

Static Methods



Java 8 gives the programmers the ability to define static methods in interfaces. As the definition goes, a static method is not attached to any instance of the class but attached to the class itself. Currently, prior to Java 8, we had to create Utility classes and helper methods to define the static methods. But Java 8 gives programmers the flexibility to add static methods in the interface to keep the code clean and understandable. To specify a static method in interface, static keyword is used at the beginning of the method signature.

Lets modify the above example, where a static method isNull() is added to the Person interface.
Code:
package example;

public interface Person {

    String getFirstName();
    String getLastName();
    
    default String getFullName() {
   	 return getFirstName() + " " + getLastName();
    }

    static boolean isEmpty(String str) {
   	 if (str == null || str.trim().length() == 0) {
   		 return true;
   	 } else {
   		 return false;
   	 }
    }
}

package example;

public class Employee implements Person {

    private String firstName;
    private String lastName;
    
    public Employee(String firstName, String lastName) {
   	 if (Person.isEmpty(firstName) || Person.isEmpty(lastName)) {
   		 throw new RuntimeException(
                "First name or last name cannot be empty.");
   	 }
   	 this.firstName = firstName;
   	 this.lastName = lastName;
    }
    
    @Override
    public String getFirstName() {
   	 return this.firstName;
    }

    @Override
    public String getLastName() {
   	 return this.lastName;
    }    
}

package example;

public class StaticMethodExample {
    public static void main(String args[]) {
   	 Person employee = new Employee("John", "Smith");
   	 System.out.println("Full Name: " + employee.getFullName());
   	 
   	 Person fakeEmployee = new Employee("", "");
   	 System.out.println("Full Name: " 
            + fakeEmployee.getFullName());
    }
}
Notice that static method in interface are accessed by calling the Classname.staticMethodName(), very similar to calling any other static methods of a class.

The output of the above code is shown below:



Default methods in interface were introduced mainly to enhance the Collections API in Java 8 to support lambda expressions, for example, forEach() method in Collection interface, to make it backward compatible with previous version of code. Static methods in interface were added to remove utility classes such as Collections for example, Collections.sort() method and move all of it’s static methods to the corresponding interface, that would be easy to find and use. So, its a topic to debate on whether default and static methods have really made java programming easier and convenient or not, but the features will help the programmers in this fast development world.

References:
  1. Oracle Java 8 SE Tutotials: http://docs.oracle.com/javase/tutori...dI/nogrow.html
  2. JOOQ blog: http://blog.jooq.org/2014/04/04/java...ide-of-java-8/
  3. Java 8 New Language features: http://www.informit.com/articles/article.aspx?p=2191423
shabbir like this