Angelika Langer - Training & Consulting
HOME | COURSES | TALKS | ARTICLES | GENERICS | LAMBDAS | IOSTREAMS | ABOUT | NEWSLETTER | CONTACT | Twitter | Lanyrd | Linkedin
About Angelika Langer  
HOME 
GENERICS 

LAMBDAS

    CONTENT
    FAQ
    LAMBDA TUTORIAL
    LAMBDA REFERENCE
    STREAM TUTORIAL
    STREAM REFERENCE
 
IOSTREAMS 
ABOUT 
NEWSLETTER 
CONTACT
Default Methods

This is a webpage devoted to lambda expressions in Java (a new language feature) and streams (new abstractions in the JDK's collection framework) - both were added to Java on March 18, 2014 with release 8. If you want to provide feedback or have any questions regarding lambda expressions in Java feel free to send me EMAIL or use the LAMBDA QUESTION form.
The Lambda Tutorial is available in PDF format (330KB) and in EPUB format (410KB) .
The Lambda Reference (note: it is an incomplete draft version) is available in PDF format (1200KB) .


Keep in mind that part of the Lambda/Streams Tutorial & References is still in draft version.

Default Methods

Default Methods

default method
Lambda expressions and method references are not the only features that have been to the language in release 8 of Java.  Java 8 also supports a novel feature named default methods .  In principle, default methods are entirely unrelated to lambda expressions.  It is just that they are the other new language feature in Java 8.  Both lambda expressions and default methods are part of the Java Specification Request JSR 335 [13] and for this reason we mention them in this tutorial.  interface evolution

Interface Evolution

Default methods are needed for interface evolution.  From the previous sections on streams and bulk operation we know that the JDK has been radically overhauled in Java 8.  Reengineering such an existing framework often involves the modification of the framework's interfaces.   As we all know, modifying an interface breaks all classes that implement the interface. In other words, changing any of the interfaces in the JDK collection framework would break millions of lines of code.  This is clearly not a viable option for a reengineering effort of the JDK.  Hence the JDK implementers had to figure a means of extending interfaces in a backward compatible way and they invented default methods. 
Default methods can be added to an interface without breaking the implementing classes because default methods have an implementation.  If every additional method in an interface comes with an implementation then no implementing class is adversely affected.  Instead of providing their own implementations of additional methods, the implementing classes can simply inherit the implementations offered by the interface's default methods.  An implementing class may choose to override the default implementation suggested by the interface.  For this reason, the default methods were initially called virtual extension methods ; they can be overridden like virtual methods inherited from a superclass.
Let us consider an example.  As mentioned earlier, the JDK collections have been extended for Java 8 and one of the changes is addition of  a forEach method to all collection in the JDK.   Hence the JDK designers wanted to add the  forEach method to the  Iterable interface, which is the topmost interface of all collections in the JDK. 
If this addition is made the traditional way (without default methods), the extended  Iterable interface looks like this:

public interface Iterable<T> {

    public Iterator<T> iterator();

    public void forEach(Consumer<? super T> consumer);

}
 
 

With this modification, every implementing class does no longer compile because it lacks an implementation of the  forEach method.  The point of a default method is that it supplies the missing implementation so that the implementing classes need not be changed.  Using a default method the  Iterable interface looks like this:

public interface Iterable<T> {

    public Iterator<T> iterator();

    public  default void forEach(Consumer<? super T> consumer) {

        for (T t : this) {

            consumer.accept(t);

        }

    }

}
 
 

The obvious difference to a regular method in a class is the  default modifier.  Otherwise, the default method has an implementation pretty much like a regular method in a class. 

In addition to the  default modifier there is another notable difference between regular methods in classes and default methods in interfaces: methods in classes can access and modify not only their method arguments but also the fields of their class.  A default method in contrast can only use its arguments because interfaces do not have state.  (The fields that you can define in an interface are not really state; they are  static final fields, i.e. symbolic names for compile-time constant values, which the compiler eliminates during compilation.)  All that the implementation of a default method can build on are its own method arguments and the other methods declared in the interface.

Take a look at the default implementation of the  forEach method above.  To illustrates the principle we slightly rewrite it; we replace the for-each loop by explicit use of an iterator. Rewritten the  Iterable interface looks like this.

public interface Iterable<T> {

    public Iterator<T>  iterator ();

    public default void forEach(Consumer<? super T>  consumer ) {

        Iterator<T> iter =  iterator ();

        while (iter.hasNext()) {

             consumer .accept(iter.next());

        }

    }

}
 
 

The  forEach method uses

its  Consumer argument, which represents the functionality that is to be applied to each element in the collection, and

the not yet implemented, abstract  iterator method that the  Iterable interface declares.
 
 

Essentially, default methods are combinations of the other methods declared in the same interface.  multiple inheritance   ambiguous inheritance

Multiple Inheritance and Ambiguities

Since classes in Java can implement multiple interfaces and each interface can have default methods, the inherited methods may be in conflict with each other if they have matching signatures.  For instance, a class  C might inherit a method  foo from both an interface  I1 and an interface  I2 .  It raises the question: which method does class  C inherit?
 
 

Diagram: Ambiguous Multiple Inheritance - Needs explicit resolution.

In such a situation the compiler cannot resolve the ambiguity and reports an error.  In order to enable the programmer to resolve the ambiguity there is syntax for explicitly stating which method class  C is supposed to inherit.  A resolution could look like this:

class C implements I1, I2 {

   public void foo() {  I1.super .foo(); }

}
 
 

This is just one example of a conceivable ambiguous inheritance of default methods.  There are numerous further examples. In some situation the compiler can resolve the situation because the language has a resolution rule for that situation.  In those few cases where the compiler reports an error (like in the example above) there is syntax for explicit resolution.  If you are interested in a more elaborate discussion of multiple inheritance in Java and/or details regarding the resolution of ambiguous multiple inheritance of default methods, please consult the section on "Default Methods" in the Lambda Reference document.


CONTENT   NEXT     INDEX
  © Copyright 1995-2013 by Angelika Langer.  All Rights Reserved.    URL: < http://www.AngelikaLanger.com/Lambdas/LambdaTutorial/lambdatutorial_5.html  last update: 8 May 2013