Java 8 Lambda Expressions

From p0f
Jump to: navigation, search

Introduction

Lambda Expressions for the Java language are meant to reduce bracket noise, thus saving time and improving readability of Java code.

However, they can only be used under certain conditions, and in this article I want to expand on what these conditions are.

What I assume

To best focus on the content of this article, I assume the reader is:

  • fluent in Java language (according to v7 language specification)

The Anatomy of a Lambda Expression

Prerequisites

Java 8 introduced functional interfaces, a special type of an interface which only has one abstract method.

The key excerpts from the Java 8 Language Specification that Lambda Expressions build upon are:

In addition to the usual process of creating an interface instance by declaring and instantiating a class (§15.9), instances of functional interfaces can be created with method reference expressions and lambda expressions (§15.13, §15.27).

and

The function type of a functional interface I is a method type (§8.2) that can be used to override (§8.4.8) the abstract method(s) of I.

The above two excerpts define when lambda expressions can be used, and define the rules for deriving the signature of that expression from the function that the interface proposes.

Building on Foundation

TROLOLO.

Advanced Shit

When the parameter types of a lambda expression are inferred, the same lambda body can be interpreted in different ways, depending on the context in which it appears.

Examples

Parameterless Void Method

Consider interface Runnable, which requires you to supply a void run() method in an implementation:

public interface Runnable {
    void run();
}

This is a common way of starting Threads:

public void startThread() {
    Runnable r = new Runnable() {
        public void run() {
            new JobRunner().doJob();
        }
    };
    Thread t = new Thread(r);
    t.start();
}

Instead of going the long way, an anonymous inner class can be used in constructor parameter:

public void startThread() {
    Thread t = new Thread(new Runnable() {
        public void run() {
            new JobRunner().doJob();
        }
    });
    t.start();
}

One can now use a lambda expression to reduce the amount of boilerplate:

public class MyCode {
    // ...
    public void startThread() {
        Runnable r = () -> { new JobRunner().doJob(); };
        Thread t = new Thread(r);
        t.start();
    }
    // ...
}

Or even?

public class MyCode {
    // ...
    public void startThread() {
        Thread t = new Thread(() -> { new JobRunner().doJob(); });
        t.start();
    }
    // ...
}