Sunday, December 11, 2022

Lambda Expression Examples in Java

As we have already seen in the post about Java lambda expressions, 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 is a common pattern in Java, from Java 8 lambda expressions provide a better alternative by implementing the abstract method of the functional interface.

In this post we'll see some examples of lambda expressions in Java like Runnable as lambda expression, Comparator as lambda expression, lambda expression implementation of Predicate functional interface.

Runnable as Lambda expression example

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.

Comparator as Lambda expression example

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.

Predicate functional interface as Lambda expression implementation

Supposing we want to use inbuilt 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 following-

  1. List of drivers (age >= 16)
  2. List of voters (age >= 18)
  3. List of 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, passing predicate as arg
    listPerson.listDrivers(personList, allDrivers);
    
    // calling method to list voters, passing predicate as arg 
    listPerson.listVoters(personList, allVoters);
    
    // calling method to list senior citizens, passing predicate as arg 
    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 provides a better alternative to provide implementation of functional interfaces.

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


Related Topics

  1. Functional Interface Annotation in Java
  2. Method Reference in Java
  3. How to Resolve Local Variable Defined in an Enclosing Scope Must be Final or Effectively Final Error
  4. Java Lambda Expression And Variable Scope
  5. Java Lambda Expressions Interview Questions And Answers

You may also like-

  1. How HashMap Works Internally in Java
  2. Executor And ExecutorService in Java With Examples
  3. final Vs finally Vs finalize in Java
  4. Difference Between throw And throws in Java
  5. static Method Overloading or Overriding in Java
  6. Covariant Return Type in Java
  7. Effectively Final in Java 8
  8. Interface Default Methods in Java 8

No comments:

Post a Comment