|
|||||||||||||||||||
HOME | COURSES | TALKS | ARTICLES | GENERICS | LAMBDAS | IOSTREAMS | ABOUT | 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) .
|
|||||||||||||||||||
Default Methods
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 |