Java Lambda Expressions Tutorial

In this Java tutorial we learn about methods without names, otherwise known as anonymous methods, or Lambda expressions.

We discuss functional interface dependency, and how to define and use lambda expressions.

Functional interfaces in Java

Lambda expressions depend on functional interfaces. Before we learn about lambda’s, let’s quickly discuss functional interfaces.

If an interface contains only one abstract method, it’s considered to be a functional interface. The single method specifies the intended purpose of the interface.

Example:
public class Program {
    public static void main(String[] args) {}
}

// the interface only has
// a single method, therefore
// it becomes a functional
// interface
interface ILog {

    public double logger();
}

We can specify explicitly that an interface is a functional interface with the @FunctionalInterface annotation.

Example:
public class Program {
    public static void main(String[] args) {}
}

@FunctionalInterface
interface ILog {

    public double logger();
}

It’s considered good practice to always be explicit and specify the annotation.

What are lambda expressions (anonymous methods)

A lambda expression is a method without a name. Lambda’s are also known as anonymous, or unnamed methods.

A lambda expression does not execute on its own. Instead, it’s used to implement a method defined by a functional interface.

How to define a lambda expression in Java

To define a lambda expression, we omit any modifier keywords, the return type and the method’s name.

We also use the lambda arrow operator, a dash symbol immediately followed by a greater than symbol -> , between the parameter list and the method body.

Syntax:
(parameters) -> {

    // lambda body
}

It may be alittle confusing at first, so let’s see how a regular method would convert into a lambda expression.

Example:
public float getPI() {
    return 3.14f;
}

// would turn into

() -> 3.14f;

If the lambda body only contains a single statement, like the example above, we can omit the curly braces.

If the lambda contains multiple statements, we must specify the code block, as well as return a value explicitly. We must also terminate the code block with a semicolon.

Example:
() -> {
    float pi = 3.14f;
    return pi;
};

Lambda’s may also have parameters.

Example:
// print a msg
(msg) -> System.out.println(msg);

// evaluate if n
// is even or odd
// and return a
// boolean
(n) -> (n % 2) == 0

How to define a lambda with a functional interface in Java

As mentioned before, lambda’s implement a method defined by a functional interface.

Let’s start by defining a functional interface.

Example:
public class Program {
    public static void main(String[] args) {}
}

@FunctionalInterface
interface ILog {

    public void logger();
}

In the example above, we specify explicitly that the interface is a functional one and create a simple method inside.

Next, let’s implement the ‘logger’ method with a lambda.

Example:
public class Program {
    public static void main(String[] args) {

        // create an instance object
        // of the interface, to assign
        // the lambda to
        ILog log;

        // store the lambda in
        // the 'log' interface object
        // and define the 'logger'
        // method's functionality
        log = () -> System.out.println("Hello, World!");

        // call the lambda
        log.logger();
    }
}

@FunctionalInterface
interface ILog {

    public void logger();
}

When we want to use parameters, we specify them in the interface method and the lambda expression.

The interface method already defines the parameter type so we can omit the type in the lambda’s parameter list.

Example:
public class Program {
    public static void main(String[] args) {

        ILog log;

        // because the method in the
        // interface contains a parameter
        // we have to add one here, but we
        // omit the type in the parameter list
        log = (msg) -> System.out.println(msg);

        // call the lambda
        // with an argument
        log.logger("Hello, World!");
    }
}

@FunctionalInterface
interface ILog {

    public void logger(String msg);
}

If the lambda expression has multiple statements, we must return a value.

Example:
public class Program {
    public static void main(String[] args) {

        // lambda with return
        IFormat htmlReady;

        htmlReady = (text) -> {
            text = "<p>" + text + "</p>";
            return text;
        };

        // non-returning lambda
        ILog log;

        log = (msg) -> System.out.println(msg);

        // call the lambdas
        log.logger( htmlReady.format("Hello, World!") );
    }
}

@FunctionalInterface
interface ILog {

    public void logger(String msg);
}

@FunctionalInterface
interface IFormat {

    public String format(String text);
}

In the example above we add another interface that will format some text with html tags to be used in an html document.

The ‘format’ lambda has more than one statement in its body, so we must return a value explicitly.

Summary: Points to remember

  • A lambda expression is a method without a name, and doesn’t require a class.
  • Lambda’s implement methods from functional interfaces.
    • A functional interface is an interface with a single abstract method inside.
    • We can, and should, specify the @FunctionalInterface annotation.
  • A lambda definition omits any modifier keywords, the return type and the method’s name.
  • A lambda definition uses the -> operator between the parameter list and method body.
  • When a lambda only contains a single statement, we may omit the body curly braces.
  • When a lambda contains more than one statement, we must explicitly return a value.
  • A lambda with a body is terminated with a semicolon after the closing curly brace.
  • Because a lambda doesn’t require a class, it makes our code simpler, shorter, and easier to read.