Java Basics

Java 8 Default Methods Tutorial

In this article we are going to explain how to use and take advantage of the possibility to implement default methods in interfaces. This is one of the most important features that are available since Java update 8.

All examples have been implemented using Eclipse Luna version 4.4 and Java version 8 update 5.

Reasons for default methods in interfaces

In “old” Java, if we want to add new methods to an existing interface, we need to implement these methods in all the classes that are currently implementing this interface. If we do not do this, we are going to get compilation errors and our code (legacy?) is not going to work anymore.

The Oracle team in charge of the Java language development had a similar problem when they wanted to implement the Stream API and other features coming out in the Java update 8.

The Collections Framework Collection interface, for example, was extended by adding methods like forEach(), stream() and parallelStream(). These methods were added directly to the interface Collection. So in order to make things work they had two options basically:

  • First one was to add implementation of these methods in all the classes that implement the Collection interface, which is quite a hard job and does not provide compatibility with old versions of Java. This means that applications, libraries and APIs that have been implemented in the past, have to be re implemented. This is just a no go.
  • The other option was to introduce default methods in the interfaces: Methods that are implemented directly in the interface do not need to be implemented in the classes.
  • If a specific class contains an implementation for a default method, this takes preference to the interface one. That means, that interfaces default methods can be overridden in the classes (but do not need to). Default methods can be added to interfaces without any need of changing existing implementing classes.

    First examples and syntax

    Basically, in order to create a default method in an interface we write something like:

    		public interface InterfaceWithDefault
    		{
    			public default void defaultMethod()
    			{
    				System.out.println( "I am the default method of the interface " );
    			}
    			
    			public void toImplementMethod();
    	

    In the code above we can see how a default method is implemented in an interface by using the keyword default.

    Diamond problem

    Several advantages can be taken with the introduction of default methods in interfaces but, on the other hand, new problems arise: one of this problems is the so called “Diamond problem”, that is, the multiple inheritance problem.

    If a class A extends more than one class B and C, and the classes B and C, both have the method bc() implemented, we have a small problem. We need a set of rules to decide what version of the method bc() is going to be used by the class A.

    This problem was solved until now in Java by preventing multiple inheritance: one class can only extend other class, not more.

    But now, with default methods being implemented in interfaces a class X can implement interfaces Y and Z with the default method yz(). The method yz() is inherited twice by the class X, so we have to decide which one to use, the one from Y or the one from Z, or no one of them and the class X has to implement itself the method yz().

    This last option is the one that Java adopted: that means, a class that implements several interfaces that have the same default method implemented, has to implement this method itself. We are going to explain this with an example.

    So we have two interfaces InterfaceAWithDefault and with a default method defaultMethod():

    		public interface InterfaceAWithDefault
    		{
    
    			public default void defaultMethod()
    			{
    				System.out.println( "I am the default method of the InterfaceAWithDefault " );
    			}
    			...
    		}
    		public interface InterfaceBWithDefault
    		{
    
    			public default void defaultMethod()
    			{
    				System.out.println( "I am the default method of the InterfaceBWithDefault " );
    			}
    			...
    		}
    	

    And a class that implements both interfaces:

    		public class ClassImplementingDefaultInterfaces implements InterfaceAWithDefault, InterfaceBWithDefault
    		{
    		...
    		}
    	

    If we do not implement the method defaultMethod() in the class ClassImplementingDefaultInterfaces we would get the following compilation error:

    		Duplicate default methods named defaultMethod with the parameters () and () are inherited from the types InterfaceBWithDefault and InterfaceAWithDefault
    	

    The solution for this error is to implement the method in the implementing class:

    		public class ClassImplementingDefaultInterfaces implements InterfaceAWithDefault, InterfaceBWithDefault
    		{
    			public void defaultMethod()
    			{
    				System.out.println( "Implemented method... " );
    			}
    		}
    	

    If we want to give preference to one of the interfaces we can call the interface’s implementation:

    		public class ClassImplementingDefaultInterfaces implements InterfaceAWithDefault, InterfaceBWithDefault
    		{
    			public void defaultMethod()
    			{
    				InterfaceAWithDefault.super.defaultMethod();
    			}
    		}
    	

    In the code above we can see how the interface method is referenced: InterfaceAWithDefault.super.defaultMethod() using the super keyword as attribute of the interface name.

    Static methods

    In combination with default methods, Java 8 offers the possibility to define static methods that can assist the default ones. The following code shows an example of this:

    		public interface InterfaceWithDefaultAndStatics
    		{
    
    		public default void defaultMethod()
    		{
    			// it is possible to use interface static methods
    			System.out.println( "I am the default method of the interface, give me five! " + giveMeFive() );
    		}
    
    		public static String giveMeFive()
    		{
    			return "5";
    		}
    		...
    	

    The method giveMeFive() is static and implemented in the interface. It can be used by other static and default methods inside the interface without any problem.

    These static methods are part of the interface and not part of the implementing classes that may implement this interface. Because of that, in order to call these static methods we should prefix them with the interface name, not the class one:

            // it is possible to call static methods directly to the interface
            InterfaceWithDefaultAndStatics.giveMeFive(); // right
    
            ClassImplementingDefaultInterface.giveMeFive(); // wrong: The method giveMeFive() is undefined for the type ClassImplementingDefaultInterface
    	

    As shown in the snippet of code above, in order to call the interface static method giveMeFive() we have to prefix it with the interface name, otherwise, if we try to use the class name for this, we would get an error.

    Until now, was common to implement static methods in utility classes that were used in several places afterwards. A good and known example for this is the java.util.Collections class where several static methods related to the interface java.util.Collection are implemented.

    It is not needed any more to implement utility classes to implement there your static methods, you can use interfaces static methods instead.

    Object class non final methods

    The Object class contains several methods that are inherited by all classes in Java (more or less). So we can think in providing default customized implementations for these methods by using interfaces default methods. Well, this is just not possible!

    For example if we try something like that:

    		public interface InterfaceWithDefaultsProhibited {                        
    			@Override
    			public default String toString(){
    			}
    		}
    	

    We will get the following compilation error:

    		A default method cannot override a method from java.lang.Object 
    	

    So, it is not permitted to override a method from java.lang.Object in an interface default one.

    Abstract classes

    Although abstract classes and default methods in interfaces have some points in common, they are not the same concept exactly; here is a list of differences:

  • Abstract classes have constructors
  • Abstract classes have a state associated to them
  • Default methods can only invoke other default or static methods from the same interface
  • Default methods are not able to reference any status of the instances or objects
  • A given class can implement only one an abstract class (no multiple inheritance for classes)
  • Bellow, we have an snippet that show one of the main differences between abstract classes and interfaces (interfaces have no state):

    		public interface InterfaceDefaultExample
    		{
    
    			int cachedTwo = -1;
    
    			public int calculateTwoPlusTwo();
    
    			public default int returnTwo()
    			{
    				if( cachedTwo != -1 ) //warning: Comparing identical expressions
    					return cachedTwo; //warning: Dead code
    				cachedTwo = 2;
    				return 2;
    			}
    		
    		}
    	

    This code does not compile, the error would be:

    	The final field InterfaceDefaultExample.cachedTwo cannot be assigned
    	

    and also some warnings as we saw in the commented code. If we would use this code in an abstract class, would be no problem, because an abstract class can make use of internal variables and change their state. Here is the code for the abstract class variation:

    		public abstract class AbstractClassExample
    		{
    			int cachedTwo = -1;
    
    			public abstract int calculateTwoPlusTwo();
    
    			public int returnTwo()
    			{
    				if( cachedTwo != -1 )
    					return cachedTwo;
    				cachedTwo = 2;
    				return 2;
    			}
    		}
    	

    Summary

    So, that is all. In this article we saw how add default implementations to interfaces methods, we explained how Java solved the diamond problem related to multiple inheritance, we commented the main differences between abstract methods in abstract classes and default methods in interfaces and we wrote down some examples of all these ones. In general, default methods are one of the new features coming in Java 8 together with Streams, Lambdas or the Date Time API that increase the design flexibility and the code quality; and, for some experts, it is the most important one.

    Download the examples

    Download
    All examples from this article (and some more) can be downloaded in the following link: defaults.

    Please take into consideration that some snippets shown in this article are not working and this is their purpose (to show what works and what does not), so not all the attached code compiles.

    Links

    If you want to find more information about default methods in interfaces or about other Java 8 new features you can visit:

  • http://www.javacodegeeks.com/2014/05/java-8-features-tutorial.html
  • http://docs.oracle.com/javase/tutorial/java/IandI/defaultmethods.html
  • Diamond problem explanation: http://en.wikipedia.org/wiki/Multiple_inheritance
  • Dani Buiza

    Daniel Gutierrez Diez holds a Master in Computer Science Engineering from the University of Oviedo (Spain) and a Post Grade as Specialist in Foreign Trade from the UNED (Spain). Daniel has been working for different clients and companies in several Java projects as programmer, designer, trainer, consultant and technical lead.
    Subscribe
    Notify of
    guest

    This site uses Akismet to reduce spam. Learn how your comment data is processed.

    0 Comments
    Inline Feedbacks
    View all comments
    Back to top button