Lambda expressions are the most touted feature of Java 8. They promise to reduce the amount of code you have to write, make your code less error-prone, and make it easier to read. Let’s understand how lambdas manage to do all this using an example.



Filtering a Collection

One of the most common operations on a collection is to filter it based on some criteria. Assuming that you have a collection of movies, you might want to remove the movies that have low ratings. The traditional way to perform this filtering is using an iterator. You loop over all the elements of the collection and remove the ones that you don’t need.

Filtering collections using a loop public class Main { public static void main(String[] args) { Collection<Movie> movies = new HashSet<>(); movies.add(new Movie("The Shawshank Redemption", 9.2)); movies.add(new Movie("The Dark Knight", 8.9)); movies.add(new Movie("Black Swan", 8.0)); Iterator<Movie> it = movies.iterator(); while (it.hasNext()) { Movie m = it.next(); if (m.getRating() < 8.5) { it.remove(); } } System.out.println(movies); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 public class Main { public static void main ( String [ ] args ) { Collection <Movie> movies = new HashSet <> ( ) ; movies . add ( new Movie ( "The Shawshank Redemption" , 9.2 ) ) ; movies . add ( new Movie ( "The Dark Knight" , 8.9 ) ) ; movies . add ( new Movie ( "Black Swan" , 8.0 ) ) ; Iterator <Movie> it = movies . iterator ( ) ; while ( it . hasNext ( ) ) { Movie m = it . next ( ) ; if ( m . getRating ( ) < 8.5 ) { it . remove ( ) ; } } System . out . println ( movies ) ; } }

The Movie class used in this example is a simple Java POJO.

Movie Class public class Movie { private String name; private double rating; public Movie(String n, double r) { this.name = n; this.rating = r; } public double getRating() { return rating; } public String getName() { return name; } @Override public String toString() { return "{" + name + ", " + rating + "}"; } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public class Movie { private String name ; private double rating ; public Movie ( String n , double r ) { this . name = n ; this . rating = r ; } public double getRating ( ) { return rating ; } public String getName ( ) { return name ; } @Override public String toString ( ) { return "{" + name + ", " + rating + "}" ; } }

Generalize using an Interface

If you want to filter the collection on multiple criteria, you need to write this kind of iterator/loop based code each time. Most of this code is boilerplate and you’d want to abstract it away. You can create an interface to represent the test you need to execute on each element (it’s generally called a predicate in programming parlance).

Predicate Interface interface Predicate<T> { boolean test(T t); } 1 2 3 interface Predicate <T> { boolean test ( T t ) ; }

Using this abstraction, you can write a general method that will be able to filter any collection given a predicate instance

Collections Utility Class class Collections { public static <T> void removeAll(Collection<T> coll, Predicate<T> pred) { Iterator<T> it = coll.iterator(); while (it.hasNext()) { T t = it.next(); if (pred.test(t)) { it.remove(); } } } } 1 2 3 4 5 6 7 8 9 10 11 class Collections { public static <T> void removeAll ( Collection <T> coll , Predicate <T> pred ) { Iterator <T> it = coll . iterator ( ) ; while ( it . hasNext ( ) ) { T t = it . next ( ) ; if ( pred . test ( t ) ) { it . remove ( ) ; } } } }

Now, you can generalize your original code by making use of anonymous inner classes.

Main class using Predicate Anonymous Inner Class import java.util.*; public class Main2 { public static void main(String[] args) { Collection<Movie> movies = new HashSet<>(); movies.add(new Movie("The Shawshank Redemption", 9.2)); movies.add(new Movie("The Dark Knight", 8.9)); movies.add(new Movie("Black Swan", 8.0)); Collections.removeAll(movies, new Predicate<Movie>() { @Override public boolean test(Movie m) { return m.getRating() < 9.0; } } ); System.out.println(movies); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 import java . util . * ; public class Main2 { public static void main ( String [ ] args ) { Collection < Movie > movies = new HashSet <> ( ) ; movies . add ( new Movie ( "The Shawshank Redemption" , 9.2 ) ) ; movies . add ( new Movie ( "The Dark Knight" , 8.9 ) ) ; movies . add ( new Movie ( "Black Swan" , 8.0 ) ) ; Collections . removeAll ( movies , new Predicate < Movie > ( ) { @ Override public boolean test ( Movie m ) { return m . getRating ( ) < 9.0 ; } } ) ; System . out . println ( movies ) ; } }

Here comes the lambda

Although this code is much more flexible, it isn’t very intuitive or easy to read. There’s a lot of boilerplate code around the single line that is the main concern here.

Collections.removeAll(movies, new Predicate<Movie>() { @Override public boolean test(Movie m) { return m.getRating() < 9.0; } } ); 1 2 3 4 5 6 7 Collections . removeAll ( movies , new Predicate < Movie > ( ) { @ Override public boolean test ( Movie m ) { return m . getRating ( ) < 9.0 ; } } ) ;

This is where the lambda expressions feature of Java 8 performs its magic. This same piece of code, when written using lambdas, looks like this.

import java.util.*; public class Main3 { public static void main(String[] args) { Collection<Movie> movies = new HashSet<>(); movies.add(new Movie("The Shawshank Redemption", 9.2)); movies.add(new Movie("The Dark Knight", 8.9)); movies.add(new Movie("Black Swan", 8.0)); Collections.removeAll(movies, m -> m.getRating() < 9.0); System.out.println(movies); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 import java . util . * ; public class Main3 { public static void main ( String [ ] args ) { Collection < Movie > movies = new HashSet <> ( ) ; movies . add ( new Movie ( "The Shawshank Redemption" , 9.2 ) ) ; movies . add ( new Movie ( "The Dark Knight" , 8.9 ) ) ; movies . add ( new Movie ( "Black Swan" , 8.0 ) ) ; Collections . removeAll ( movies , m -> m . getRating ( ) < 9.0 ) ; System . out . println ( movies ) ; } }

Without a doubt, this code is much more concise than before. It is quite obvious what is going on here. You want to remove all elements from the collection movies where for element m , the rating is less than 9.0.

Internals

But how does it work internally? From the method signature of removeAll() , the compiler knows that the second argument is of type Predicate . Moreover, the Predicate interface has only one method. That method takes a single argument of type T and from the context of the call, the compiler knows that T is bound to type Movie in this case. Using all this information, it can create an anonymous inner class (similar to our own implementation above) on its own. In a sense, lambda expressions are just “syntactic sugar” to simplify the code.

Update May 30, 2014 Thanks to Mike and Jonathan of the Toronto Java Users Group (and Reddit users jamanifin, neutronbob & nicoulaj) for pointing out that lambdas do not create anonymous inner classes. Mike looked at the byte code that’s generated when using the built-in java.util.Collection.removeIf method. With Lambdas: 66: invokedynamic #16, 0 // InvokeDynamic #0:test:()Ljava/util/function/Predicate; 71: invokeinterface #17, 2 // InterfaceMethod java/util/Collection.removeIf:(Ljava/util/function/Predicate;)Z 1 2 66 : invokedynamic #16, 0 // InvokeDynamic #0:test:()Ljava/util/function/Predicate; 71 : invokeinterface #17, 2 // InterfaceMethod java/util/Collection.removeIf:(Ljava/util/function/Predicate;)Z Without Lambdas: 66: new #16 // class Main2$1 69: dup 70: invokespecial #17 // Method Main2$1."<init>":()V 73: invokeinterface #18, 2 // InterfaceMethod java/util/Collection.removeIf:(Ljava/util/function/Predicate;)Z 1 2 3 4 66 : new #16 // class Main2$1 69 : dup 70 : invokespecial #17 // Method Main2$1."<init>":()V 73 : invokeinterface #18, 2 // InterfaceMethod java/util/Collection.removeIf:(Ljava/util/function/Predicate;)Z This also proves that while lambdas may seem like syntactic sugar, they are definitely much more. Thanks guys.

Default Methods