Lambda Expressions in Java 8

Mike Duigou announced here that the Iteration 1 of Lambda Libraries is complete which includes support for defender methods, enhancement of the collection apis among other changes.

also read:

Before proceeding further its good to read about Functional Interfaces and Defender Methods to some extent.

Lets dive into an example, consider sorting of Person objects where each Person would have firstName, lastName, dateOfBirth, placeOfBirth

class Person {

  public Person(String fName,
                String lName,
                Date dob,
                String place)
  {
    firstName = fName;
    lastName = lName;
    dateOfBirth = dob;
    placeOfBirth = place;
  }

  @Override
  public String toString(){
    return firstName+" "+lastName;

  }
  String firstName;
  String lastName;
  Date dateOfBirth;
  String placeOfBirth;
}

Lets see how we can sort this with and without using lambda expressions

public class LambdaBasicDemo {

  public static void main(String[] args) {
    List<Person> people = createPeople();

    // Sorting pre Lambda Expression era
    //Sorting by firstName
    Collections.sort(people,new Comparator<Person>() {
      @Override
      public int compare(Person o1, Person o2) {
        return o1.firstName.compareTo(o2.firstName);
      }
    });
    System.out.println("Firstname sort: "+people);

    //Sorting using Lambda expressions and updated collection API
    //Sorting by lastName
    people.sort((o1,o2) -> {
      return o1.lastName.compareTo(o2.lastName);
    });
    System.out.println("Lastname sort:" +people);

  }

  static List<Person> createPeople(){
    Calendar calendar = Calendar.getInstance();
    calendar.set(1900, Calendar.JANUARY,01,12,00);
    List<Person> people = new ArrayList<>();
    Person person = new Person("Raju","Sarkar",calendar.getTime(),"Delhi");
    people.add(person);

    calendar.set(1950,Calendar.JUNE,30,12,30);
    person = new Person("Anant","Patil", calendar.getTime(),"Pune");
    people.add(person);

    calendar.set(1950,Calendar.DECEMBER,30,12,30);
    person = new Person("Danny","Great", calendar.getTime(),"London");
    people.add(person);

    return people;
  }
}

The output would be:

Firstname sort: [Anant Patil, Danny Great, Raju Sarkar]
Lastname sort:[Danny Great, Anant Patil, Raju Sarkar]

You all are aware of how the collections are sorted using the Collection API and Comparator so I am not going into that. There’s an interesting syntax which uses a dash(-) and an greater than symbol(>) [dash-rocket], lets look into a bit of detail about this syntax:

//Sorting using Lambda expressions and updated collection API
//Sorting by lastName
people.sort((o1,o2) -> {
  return o1.lastName.compareTo(o2.lastName);
});

There obvious difference between the verbosity of the code for sorting by creating anonymous inner class and by using Lambda expressions. The Lambda expression consists of lambda parameters and Lambda body. A Lambda expression is represented as () -> {} where () contains the lambda parameters and the {} contains the lambda body. A lambda expression can be void returning or value returning i.e can return nothing or return result of some expression.

In the above example, we are constructing a lambda expression for the functional interface Comparator with a functional descriptor (T o1, T o2) -> int.

Note: Something interesting to note here is that with Java 8 the Comparator interface has 2 more methods

Comparator<T> reverse() default {
  return Collections.reverseOrder(this);
}
Comparator<T> compose(Comparator<? super T> other) default {
  return Comparators.compose(this, other);
}

We would like to keep this confusion aside for time being and I will get back on this and explain as to why and how the defender methods are not considered. If someone if aware of the reason, please add them as comments.

Digging deeper into the lambda expression, the (o1, o2) indicates the lambda parameters. The type information for o1 and o2 are inferred from the context in which it is being used, and in our case they are of type Person. The {return o1.lastName.compareTo(o2.lastName);} is the lambda body.

Advantages of using Lambda expressions over Anonymous inner class approach:

  • Lambda expressions are lighter on code than the anonymous inner classes.
  • An advantage of using Lambda expressions is the resolution of this and super when used within the Lambda expression. In case of anonymous inner class approach the this and super are resolved to the anonymous inner class. And this is not at all useful because there’s nothing that one would want from the anonymous inner class. But in case of lambda expressions these resolve to the enclosing class.
  • Permissibility of use of effectively final variables in lambda expressions, where as only final variables can be used in local inner classes

Interestingly, compiling LambdaBasicDemo.java gives 3 class files (apart from Person.class): LambdaBasicDemo.class, LambdaBasicDemo$1.class, LambdaBasicDemo$2.class.

  • LambdaBasicDemo.class corresponds to the public class LambdaBasicDemo.
  • LambdaBasicDemo$1.class corresponds to the anonymous inner class for Comparator
  • and LambdaBasicDemo$2.class corresponds to the lambda expression. So under the hood, the compiler wraps this lambda expression with a new class and then instantiates the same.

That’s pretty much it for a sneak peak. Stay tuned for lot more as I continue to explore the feature.

Comments

comments

About Mohamed Sanaulla

In his day job he works on developing enterprise applications using ADF. He is also the moderator of JavaRanch forums and an avid blogger.

Speak Your Mind

*