What Are Default Methods in Java 8

Default methods were added in Java 8 to allow adding of new methods to interface without breaking existing implementing classes.  Using default methods we can add functionality to existing classes which implemented a common interface.

Note – All the Java source files in this project can be found at https://github.com/freetipscentral/java8-defaultmethod

Here is one example of Default method

Lets assume that we have a GenericRemote interface and two classes which implement the interface.

package com.freetipscentral.defaultmethod;

public interface GenericRemote {
  
  public void startDevice();
}

 

package com.freetipscentral.defaultmethod;

public class TVRemote implements GenericRemote {
  public void startDevice(){
    System.out.println("TV Started");
  }
}
package com.freetipscentral.defaultmethod;

public class MusicSystemRemote implements GenericRemote {
  public void startDevice(){
    System.out.println("Music System Started");
  }
}

In the above example you can see that two classes TVRemote and MusicSystemRemote implementing the interface GenericRemote hence they also implement the method startDevice().

Now consider the situation where in you need to add one more method stopDevice() to the interface GenericRemote interface.

Before Java 8 as soon as you add that method to the GenericRemote interface all the classes below will start having compilation problems.  You can solve the compilation problems by implementing the method in all the classes which implement this interface.  Same happens in Java 8 also.

But Java 8 has a more elegant solution for this.  That is called Default method.  Default method are a way to add a default implementation of the interface method on the interface itself.  That way if the interface undergoes changes after it has been implemented by many classes, those classes will not have compilation errors.

How to Add a Default Implementation Method

To add a default implementation add the keyword default at the start of the method signature and then implement the method.  Here is how the above implementations will look like after adding the default method.  Notice how the implementing classes have not undergone any changes.

package com.freetipscentral.defaultmethod;

public interface GenericRemote {
 
 public void startDevice();
 
 default public void stopDevice() {
 System.out.println("Default Stop Device");
 }
}
package com.freetipscentral.defaultmethod;

public class TVRemote implements GenericRemote {
  public void startDevice(){
    System.out.println("TV Started");
  }
}
package com.freetipscentral.defaultmethod;

public class MusicSystemRemote implements GenericRemote {
  public void startDevice(){
    System.out.println("Music System Started");
  }
}

Do The Implementing Classes Have Choice to Overriding Default Methods

Yes implementing classes can always override the default method and add their own implementation.  That way they can have the best of both worlds.

For example TVRemote class can always override the default implementation as below.

package com.freetipscentral.defaultmethod;

public class TVRemote implements GenericRemote {
  public void startDevice(){
    System.out.println("TV Started");
  }
  
  @Override
  public void stopDevice() {
    System.out.println("TV Stopped");
  }
}

 

Why Default methods were added to Java 8

Default methods were added to Java so that backwards compatibility could be maintained with older collection framework.  One of the new method added to the Collection interface is forEach.  forEach is an internal iterator which has been  added to Iterable interface in Java 8.  Collection interface extends Iterable interface.  This method helps in iterating through the objects in the collection.  For example consider the following example –

Here is what is being done in the code.

  1. Create a list of Students.
  2. Add Student objects to the list
  3. Iterate through the list and print the students.

If you notice carefully we are using forEach which is an internal iterator.  Since this is new addition to the Collection framework  all the previously written codes (running in millions of lines) which used Collection interface such as List or Set would have failed.  Hence Java 8 added the default method so that the code remains backward compatible.  If you see the Oracle documentation on Iterable interface you will see that forEach is a default method.  Here is the link to Oracle documentation on Iterable interface.

package com.freetipscentral.defaultmethod;

import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;

import com.freetipscentral.defaultmethod.domain.Student;

public class StudentManager {
  public static void main(String args[]) {
    List<Student> students = new ArrayList<Student>();
    
    //Create Students and add to list
    Student student1 = new Student("Karen",1);
    Student student2 = new Student("Rahul",2);
    students.add(student1);
    students.add(student2);
    
    //Iterate through the list and print the student objects
    students.forEach(new Consumer<Student>() {
      public void accept(Student s) {
        System.out.println(s);
      }
    });
  }
}

What happens when a class inherits two interfaces with default methods with same name

If a class implements two interfaces with same default method name then it will cause compile error in the class.  The solution is to implement the default method in the class.

What Happens When an Interface Extends Another Interface With Default Method

If an interface extends another interface which has default method then the interface and its implementing classes also have access to the default method.

However the child interface can also make it abstract.  It the child interface makes it abstract then the implementing classes of the child interface have to implement the method.  Here is an example of how child interface can make the default method abstract.  All classes implementing MobileRemote need to implement stopDevice() method.

package com.freetipscentral.defaultmethod;

public interface MobileRemote extends GenericRemote {
  public void stopDevice();
}

The child interface can also override the default interface with its own default method.  In this case the implementing classes of the child interface can use the default method of the child interface.   Here is an example of how child interface can override the default method.

package com.freetipscentral.defaultmethod;

public interface CarRemote extends GenericRemote {
  default public void stopDevice() {
    System.out.println("Stop the Car");
  }
}

 

 

Lambda Expression Tutorial

Lambda expressions are one of the new additions to Java 8.  It is also one of the most talked about and exiting features of Java 8.  We will cover what exactly are Lambda expressions and some examples in this article.

What are Lambda Expressions?

Lambda expressions are a way use a expression to represent function calls which are usually on anonymous classes.  Usually anonymous inner classes have just one method and extend some interface.  The entire purpose of writing anonymous inner classes is to implement a single method.  Lambda expressions can help us reduce the code written around anonymous inner classes by reducing to to a single statement.

Here is a simple example of Lambda expression –

( i ) -> (System.out.println(i));

Let us see an example.

In the following class following is happening –

Let us assume that you want to sort a array list of Integers using a anonymous class which implements Comparator interface.  Here are the steps –

  1. Initialize a ArrayList of integers. (Line 10)
  2. We want to sort the numbers in the list so we take help of anonymous class which implements Comparator interface (Line 11).  There is only one method inside it called compare which contains the logic for comparison.  We call the compare method in the instance of the anonymous class (Line 12).  This method compares the values in the list and returns a sorted list.
  3. Once the list is sorted we print the list (Line 17 – 20).
package com.freetipscentral.domain;

import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

public class LambdaExample1 {
  public static void main(String args[]) {
    List<Integer> numbers = Arrays.asList(1,2,3,4,5,6,7,8,9,20);
    Collections.sort(numbers, new Comparator<Integer>(){
      public int compare(Integer i1, Integer i2){
        return i1.compareTo(i2);
      }
    });
    
    for(Integer i : numbers) {
      System.out.println(i);
    }
  }
}

Here is the output of above code –

1
2
3
4
5
6
7
8
9
20

Lambda Expression For the Above Code

The above code can also be written using Lambda expressions.  Once we translate the Anonymous class to Lambda expression here is how the class looks like –

package com.freetipscentral.domain;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;

public class LambdaExample1 {
  public static void main(String args[]) {
    List<Integer> numbers = Arrays.asList(1,2,3,4,5,6,7,8,9,20);
    Collections.sort(numbers, (Integer i1, Integer i2) -> i1.compareTo(i2));
    
    for(Integer i : numbers) {
      System.out.println(i);
    }
  }
}

In the code above the actual Lambda expression is only the following code.

(Integer i1, Integer i2) -> i1.compareTo(i2)

If you run the above class the output would be same as above.  However there are two things which have happened in the code. Firstly the number of lines of code has decreased and secondly code is also simpler to understand.  If you do not find it east then do not worry.  I will explain how to do it.

Steps to reduce anonymous class function call to Lambda expressions

There are only three conceptual things you need to take care while converting a function call to Lambda expression.

  1. You only need the parameter list on the left and method body on the right.
  2. Parameter and the method body will be separated by ->
  3. Remove everything else including name of the method and return type.  They are all inferred.  The return statement is also not needed as that is inferred.

Let us see the above steps in the following example where we will convert the function call to Lambda expression.

Collections.sort(numbers, new Comparator<Integer>(){
  public int compare(Integer i1, Integer i2){
    return i1.compareTo(i2);
  }
});

The anonymous class starts at new Comparator ...

Remove from new till end of compare.  You will have the following code.

Collections.sort(numbers, (Integer i1, Integer i2){
    return i1.compareTo(i2);
  }
});

Replace { with -> at the end of the first line. Also remove the return keyword at the beginning of second line as that is implicit.

Collections.sort(numbers, (Integer i1, Integer i2) ->
    i1.compareTo(i2);
  }
});

Last step is to remove the braces for the function ending and the anonymous class at the end.  After you remove here is the code.

Replace { with -> at the end of the first line.

Collections.sort(numbers, (Integer i1, Integer i2) ->
  i1.compareTo(i2);
);

Here is the code after formatting.

Collections.sort(numbers, (Integer i1, Integer i2) -> i1.compareTo(i2);
);