Java 8 Features in a nutshell – Lambda expressions and method references

This is second post about Java 8 features in a nutshell. As you remember, last one was about Optional class.

Today I am going to talk about one of the best features of Java 8 which will make your code better and easier to read: Lambda expressions. So what is lambda expression anyway?

If you will sit back and think about evolution of development approach you can remember that first there was code, then there were functions, then there were modules and then OOP. Java is OOP language and everything is an object in Java. yep, yep, apart from primitives. That means that each method you create in java belongs to some class.

Apparently, this introduces some difficulties: for example when you have to create something as simple as Thread doing some task, you have to create Anonymous class which will hold method which you want to execute, which is ok, but creates a lot of boilerplate code.

In that light you can think about lambdas as functions, which are “not bound” to any class or identifier. They make usual tasks simpler and allows express your thoughts in more concise way.

Enough talking, lets look at some code. Lets start with thread example, here what we had to do in Java 7:

@Test
public void beforeLambda() throws InterruptedException {
    final CountDownLatch latch = new CountDownLatch(1);

    final Thread thread = new Thread(new Runnable() {
        @Override
        public void run() {
            latch.countDown();
        }
    });

    thread.start();
    assertTrue(latch.await(1, TimeUnit.SECONDS));
}

Looks familiar, isn’t it? But it has 4 lines of boilerplate code when all you actually wanted to express was “I want to call latch.countDown() in another thread”. Lets see how you can do using lambda expressions in Java 8 :

@Test
public void withLambda() throws InterruptedException {
    CountDownLatch latch = new CountDownLatch(1);

    final Thread thread = new Thread(() -> latch.countDown());

    thread.start();
    assertTrue(latch.await(1, TimeUnit.SECONDS));
}

Looks much better, isn’t it?  I think you already understand what is happening here, but let me explain:

  1. () -> latch.countDown() is lambda expression which creates lambda function which takes no arguments (empty parenthesis) and executes only one line of code
  2. Lambda expressions has access to all the scope variables (include class variables) like Java 7 anonymous functions. Important note: latch is not defined as final here, but it has to be effectively final or declared as final. Behaviour here is same as in methods of anonymous classes, you can’t assign anything else to latch, for example if you put latch = null after thread.start, code would not compile.
  3. There is almosst no boilerplate code.

But what if you want to execute multiple statements? You just need to create a statement block:

@Test
public void withLambdaBlock() throws InterruptedException {
    CountDownLatch latch = new CountDownLatch(1);

    final Thread thread = new Thread(() -> {
        latch.countDown();
        System.out.printf("Thread exiting");
    });

    thread.start();
    assertTrue(latch.await(1, TimeUnit.SECONDS));
}

But wait, we still have boilerplate piece of code () -> which is not required if you are planning to do simple operation of calling one method on latch object. Java 8 allows you to get rid of that boilerplate code as well using method references:

@Test
public void withLambdaMethodReference() throws InterruptedException {
    CountDownLatch latch = new CountDownLatch(1);

    final Thread thread = new Thread(latch::countDown);

    thread.start();

    assertTrue(latch.await(1, TimeUnit.SECONDS));
}

That looks nice, isn’t it? I mean after seeing this, how you can ever code on Java 7, right? :)

Now, lets see how you can use lambda expressions when you need to pass some arguments. We are going to use new Iterable method forEach which appeared in Java 8. I believe code will be self-explanatory:

@Test
public void argumentLambda() {
    List<String> list = Arrays.asList("apple", "carrot", "apricot");

    list.forEach((String s) -> System.out.println(s));

    list.forEach(s -> System.out.println(s)); // Java is able to infer type of S from definition of forEach

    list.forEach(System.out::println); // or we can just use method reference
}

We are creating list and iterate over it using lambda expression and method reference. All three forEach lines do exactly same thing, and demonstrates how java 8 enables you to write less of boilerplate code.

Now, please take a moment and think about how much clearer your code will be after you replace all your addActionListener(new ActionListener() {...   with one line of method reference getting exactly same functionality. And cherry on top: it is not just syntax sugar, under the hood compiler will actually create more efficient code for you.

I hope now you (better) understand lambda expressions and method references in Java 8. Please use comment form below if you have any questions.

Other posts about Java 8 features: