Wednesday, 10 June 2015

Lambda expression examples

As we have already seen in the post about lambda expression, they implement the abstract method of the functional interface. In that way lambda expressions can provide a compact and easy to read code which is not repetitive by using them in place of anonymous classes.

Using functional interfaces with anonymous inner classes are a common pattern in Java, from Java 8 lambda expressions provide a better alternative by implementing the abstract method of the functional interface.

Let's see some examples -

Lambda expression with Runnable

It is very common to implement the run method of runnable interface as an anonymous class, now same can be done with lambda expression in fewer lines increasing readability.

public class RunnableLambda {
    public static void main(String[] args) {
        // Runnable using anonymous class
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("Runnable with anonymous");
            }
        }).start();
        
        // Runnable using lambda
        new Thread(()->System.out.println("Runnable Lambda")).start();

    }

}

It can be seen how concise the implementation becomes with lambda expression.

Lambda expression with comparator

In this example we'll have a list of Person object and they are sorted on first name using comparator.

Person class

public class Person {
    private String firstName;
    private String lastName;
    private int age;
    private char gender;
    Person(String firstName, String lastName, int age, char gender){
        this.firstName = firstName;
        this.lastName = lastName;
        this.age = age;
        this.gender = gender;
    }
    
    public String getFirstName() {
        return firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public int getAge() {
        return age;
    }
    public char getGender() {
        return gender;
    }
    
    public String toString(){
        StringBuffer sb = new StringBuffer();
        sb.append(getFirstName()).append(" ");
        sb.append(getLastName()).append(" ");
        sb.append(getAge()).append(" ");
        sb.append(getGender());
        return sb.toString();
        
    }
}

// Functional interface
@FunctionalInterface
interface IMyInterface {
    Person getRef(String firstName, String lastName, int age, char gender);
}

public class LambdaExpressionDemo {
    public static void main(String[] args) {
        List<Person> personList = createList();
        
        // comparator implementation as anonymous class
        // and sorting the list element on the basis of first name
        Collections.sort(personList, new Comparator<Person>() {
            public int compare(Person a, Person b) {
                return a.getFirstName().compareTo(b.getFirstName());
             }
        });
        
        System.out.println("Sorted list with anonymous implementation");
        for(Person p : personList){
            System.out.print(p.getFirstName() + " ");
        }
        
        // creating the same list again to use with lambda expression
        personList = createList();
        // Providing the comparator functional interface compare
        /// method as lambda exression
        Collections.sort(personList, (Person a, Person b) -> 
            a.getFirstName().compareTo(b.getFirstName()));
        System.out.println("Sorted list with lambda implementation");
        // Using the new ForEach loop of Java 8 
        // used with lambda expression
        personList.forEach((per) -> System.out.print(per.getFirstName() + " "));
    }
    
    // Utitlity method to create list
    private static List<Person> createList(){
        List<Person> tempList = new ArrayList<Person>();
        IMyInterface createObj = Person::new;
        Person person = createObj.getRef("Ram","Tiwari", 50, 'M');
        tempList.add(person);
        person = createObj.getRef("Prem", "Chopra", 13, 'M');
        tempList.add(person);
        person = createObj.getRef("Tanuja", "Trivedi", 30, 'F');
        tempList.add(person);
        person = createObj.getRef("Manoj", "Sharma", 40, 'M');
        tempList.add(person);
        System.out.println("List elements are - ");
        System.out.println(tempList);
        return tempList;
    }
}

Output

List elements are - 
[Ram Tiwari 50 M, Prem Chopra 13 M, Tanuja Trivedi 30 F, Manoj Sharma 40 M]
Sorted list with anonymous implementation
Manoj Prem Ram Tanuja List elements are - 
[Ram Tiwari 50 M, Prem Chopra 13 M, Tanuja Trivedi 30 F, Manoj Sharma 40 M]
Sorted list with lambda implementation
Manoj Prem Ram Tanuja

Here I have used some of the features of Java 8 like Constructor reference using Double colon operator, which is this line IMyInterface createObj = Person::new;

Also used the new forEach statement in Java 8 with lambda expression, which is this line personList.forEach((per) -> System.out.print(per.getFirstName() + " "));

Same way lambda expression can be used with other functional interfaces like Callable, ActionListener etc.

Lambda expression with inbuilt functional interfaces

With Java 8 many new functional interfaces are being defined, in fact there is a whole new package java.util.function added with many functional interfaces. The interfaces in this package are general purpose functional interfaces used by the JDK, and are available to be used by user code as well.

The following are some of the examples of new functional interfaces in Java 8-

public interface Predicate<T> {
  boolean test(T t);
}
 
public interface Function<T,R> {
  R apply(T t);
}
 
public interface BinaryOperator<T> {
  T apply(T left, T right);
}
 
public interface Consumer<T> {
  void accept(T t);
}
 
public interface Supplier<T> {
  T get();
}

Starting with Java 8 these functional interfaces can be implemented by means of lambda expressions and method references.

We have already seen in the above examples how using lambda expressions we can solve the vertical problem associated with anonymous classes and make the code concise and more readable. Here let's see an example using one of the inbuilt functional interface.

Supposing we want to use already given functional interface named Predicate declared as follows:

public interface Predicate<T> {
  boolean test(T t);
}

We have a class person and using that person list we want to implement a search criteria where we want to search and print the list of drivers (age >= 16), of voters (age >= 18) and senior citizens (age >= 60). We'll use the inbuilt functional interface Predicate to set up the search criteria. Note that we don’t need to explicitly write the Predicate interface as it is already available, we just need to import it from java.util.function package.

Person Class

public class Person {
    private String firstName;
    private String lastName;
    private int age;
    private char gender;
    public Person(String firstName, String lastName, int age, char gender){
        this.firstName = firstName;
        this.lastName = lastName;
        this.age = age;
        this.gender = gender;
    }
    
    public String getFirstName() {
        return firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public int getAge() {
        return age;
    }
    public char getGender() {
        return gender;
    }
    
    public String toString(){
        StringBuffer sb = new StringBuffer();
        sb.append(getFirstName()).append(" ");
        sb.append(getLastName()).append(" ");
        sb.append(getAge()).append(" ");
        sb.append(getGender());
        return sb.toString();
        
    }
}
@FunctionalInterface
interface IMyFunc {
    Person getRef(String firstName, String lastName, int age, char gender);
}

public class LambdaDemo {
    
    public static void main(String args[])
    {
        List<Person> personList = createList();
        ListPerson listPerson = new ListPerson();
        //Predicates
        // For age >= 16
        Predicate<Person> allDrivers = p -> p.getAge() >= 16;
        // For age >= 18
        Predicate<Person> allVoters = p -> p.getAge() >= 18;
        // For age >= 60
        Predicate<Person> allSeniorCitizens = p -> p.getAge() >= 60;
        // calling method to list drivers 
        listPerson.listDrivers(personList, allDrivers);
        
        // calling method to list voters 
        listPerson.listVoters(personList, allVoters);
        
        // calling method to list senior citizens 
        listPerson.listSeniorCitizens(personList, allSeniorCitizens);
        
        
    }
    
     // Utitlity method to create list
     private static List<Person> createList(){
         List<Person> tempList = new ArrayList<Person>();
        // Constructor reference
         IMyFunc createObj = Person::new;
         Person person = createObj.getRef("Ram","Tiwari", 50, 'M');
         tempList.add(person);
         person = createObj.getRef("Prem", "Chopra", 13, 'M');
         tempList.add(person);
         person = createObj.getRef("Tanuja", "Trivedi", 30, 'F');
         tempList.add(person);
         person = createObj.getRef("Manoj", "Sharma", 40, 'M');
         tempList.add(person);
         person = createObj.getRef("John", "Trevor", 70, 'M');
         tempList.add(person);
         person = createObj.getRef("Alicia", "Sliver", 17, 'F');
         tempList.add(person);
         System.out.println("List elements are - ");
         System.out.println(tempList);
         return tempList;
     }
}

class ListPerson {
    // method to list drivers
    public void listDrivers(List<Person> personList, Predicate<Person> pred){
        List<Person> driverList = new ArrayList<Person>();
        for(Person person : personList){
            if (pred.test(person)){
                driverList.add(person);    
            }
        }
        System.out.println("List of drivers ");
        printList(driverList);
    }
    
    // method to list voters
    public void listVoters(List<Person> personList, Predicate<Person> pred){
        List<Person> voterList = new ArrayList<Person>();
        for(Person person : personList){
            if (pred.test(person)){
                voterList.add(person);    
            }
        }
        System.out.println("List of voters ");
        printList(voterList);
    }
    
    // method to list senior citizens
    public void listSeniorCitizens(List<Person> personList, Predicate<Person> pred){
        List<Person> seniorCitizenList = new ArrayList<Person>();
        for(Person person : personList){
            if (pred.test(person)){
                seniorCitizenList.add(person);    
            }
        }
        System.out.println("List of senior citizens ");
        printList(seniorCitizenList);
    }
 
    // Method used for printing the lists
    private void printList(List<Person> personList){
        personList.forEach((p) -> System.out.print(" FirstName - " + p.getFirstName()  
                + " LastName - " + p.getLastName() + " Age - " + p.getAge()));
        System.out.println("");
    }
}

It can be seen how concise and readable the code becomes and it is also non-repetitive, if we were using anonymous classes to write these search criteria we would have done the same chore of taking new instance of interface Predicate and overriding the test method for each search criteria. The anonymous class implementation for getting the list of drivers would have looked like this.

listPerson.listDrivers(personList, new Predicate<Person>(){
   @Override
   public boolean test(Person p){
       return p.getAge() >=16;
   }
});

So it can be seen how lambda expression can help with solving the vertical problem associated with anonymous class and provide a better alternative to provide implementation of functional interfaces.

That's all for this topic Lambda expression examples. If you have any doubt or any suggestions to make please drop a comment. Thanks!


Related Topics

  1. Overview of lambda expressions
  2. Functional interfaces & lambda expression
  3. Functional interface annotation in Java 8
  4. Lambda expression and variable scope
  5. Lambda expression and exception handling
  6. Method reference in Java 8

You may also like -

No comments:

Post a Comment