Default Methods in Java 8

In this article, I’ll try to explain what are default methods in Java 8, why they are useful and how they can be used to enhance the design of your code.

Default methods are added to Java 8 largely to support library designers by enabling them to write more evolvable interfaces. Java 8 introduces “Default Method” or (Defender methods) new feature, which allows developers to add new methods to the interfaces without breaking the existing implementation of these interfaces. Default methods are non-abstract and marked by the modifier default. It provides flexibility to allow the interface define implementation which will use as default in the situation where a concrete class fails to provide an implementation for that method.

Let’s consider this piece of code to understand how it works, in this example, I’ve just added a new default method newDefaultMethod() to the existing ‘old’ interface.

/**
 * Created by marom on 20/11/16.
 */
public interface SomeOldInterface {

    public void existingMethod();

    default public void newDefaultMethod() {

        System.out.println("New default method is added in the interface");

    }
}

An existing implementation of that interface will successfully compile without errors.

/**
 * Created by marom on 20/11/16.
 */
public class SomeOldInterfaceImpl implements SomeOldInterface {

    public void existingMethod() {
        // existing implementation is here…
    }
}

 

Why Default Method?

Reengineering an existing JDK framework is always very complex. Modify one interface in JDK framework breaks all classes that extends the interface which means that adding any new method could break millions of lines of code. Therefore, default methods have introduced as a mechanism to extending interfaces in a backwards compatible way.

Default methods can be provided to an interface without affecting implementing classes as it includes an implementation. If each added method in an interface defined with implementation then no implementing class is affected. An implementing class can override the default implementation provided by the interface.

For Java 8, the JDK collections have been extended and forEach method is added to the entire collection (which work in conjunction with lambdas).

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

The same mechanism has been used to add Stream in JDK interface without breaking the implementing classes.

When to Use Default Method Over Abstract Classes?

After introducing Default Method, it seems that interfaces and abstract classes are same. However, they are still a different concept in Java 8.

Abstract classes can still do more in comparison to Java 8 interfaces:

  • An abstract class can have a constructor.
  • Abstract classes are more structured and can hold a state.

Abstract classes are similar to interfaces. You cannot instantiate them, and they may contain a mix of methods declared with or without an implementation.

However, with abstract classes, you can declare fields that are not static and final, and define public, protected, and private concrete methods.

With interfaces, all fields are automatically public, static, and final, and all methods that you declare or define (as default methods) are public. In addition, you can extend only one class, whether or not it is abstract, whereas you can implement any number of interfaces.

Conceptually, the main purpose of defender methods is a backwards compatibility after an introduction of new features (as lambda functions) in Java 8.

Are the abstract classes still useful in that scenario?

Yes. They are still useful. They can contain non-static, non-final methods and attributes (protected, private in addition to public), which is not possible even with Java-8 interfaces.

Default Method and Multiple Inheritance Ambiguity Problems.

Since java class can implement multiple interfaces and each interface can define default method with same method signature, therefore, the inherited methods can conflict with each other.

Let’s check this example:

/**
 * Created by marom on 20/11/16.
 */
public interface InterfaceA {

    default void defaultMethod() {

        System.out.println("Interface A default method");

    }
}
/**
 * Created by marom on 20/11/16.
 */
public interface InterfaceB {

    default void defaultMethod() {

        System.out.println("Interface B default method");

    }
}
/**
 * Created by marom on 20/11/16.
 */
public class InterfaceABImpl implements InterfaceA, InterfaceB {

}

The above code will fail to compile with the following error:

java: class Impl inherits unrelated defaults for defaultMethod() from types InterfaceA and InterfaceB

In order to fix this class, we need to provide default method implementation:

/**
 * Created by marom on 20/11/16.
 */
public class InterfaceABImpl implements InterfaceA, InterfaceB {

    public void defaultMethod() {
        // default method implementation
    }
}

Further, if we want to invoke default implementation provided by any of super interface rather than our own implementation, we can do so as follows:

/**
 * Created by marom on 20/11/16.
 */
public class InterfaceABImpl implements InterfaceA, InterfaceB {

    public void defaultMethod() {
        // default method implementation
        InterfaceA.super.defaultMethod();
    }
}

 

Difference Between Default Method and Regular Method

Default Method is different from the regular method in the sense that default method comes with default modifier. Additionally, methods in classes can use and modify method arguments as well as the fields of their class but default method, on the other hand, can only access its arguments as interfaces do not have any state.

 

In summary, Default methods enable to add new functionality to existing interfaces without breaking older implementation of these interfaces.

When we extend an interface that contains a default method, we can perform following,

  • Not override the default method and will inherit the default method.
  • Override the default method similar to other methods we override in a subclass.
  • Redeclare default method as abstract, which force a subclass to override it.

Difference Between Abstract Class and Interface in Java

A short comparison of an abstract class and interface in Java.

 Abstract Classes  Interfaces
 abstract class can have static, final or static final variable with any  access specifier  interface can have only static final (constant) variable i.e. by default
 abstract class can extend from a class or from an abstract class  interface can extend only from an interface
 in abstract class keyword ‘abstract’ is mandatory to declare a method  as an abstract  in an interface keyword ‘abstract’ is optional to declare a method as  an abstract
 abstract class can have both abstract and concrete methods  interface can have only abstract methods
 abstract class can have protected , public and public abstract methods  interface can have only public abstract methods i.e. by default
 a class can extend only one abstract class  a class can implement any number of interfaces
 abstract class can extend only one class or one abstract class at a time  interface can extend any number of interfaces at a time