JavaWorking with Lambda Expressions in Java

Working with Lambda Expressions in Java

Java Developer Tutorials

In Java, a lambda expression is a block of code that accepts arguments and returns a value. The lambda expression was originally introduced in Java 8, and it improves Java’s expressive capabilities. This article talks about lambda expressions and how we can work with them in Java.

What is a Lambda Expression?

Lambda expressions are anonymous methods that do not have any name and belong to any class. Lambda expressions are a part of the java.util.function package. You can use lambda expressions in Java to implement callbacks</b or listeners.

Lambda Expressions are the building blocks of functional programming in Java. Each lambda expression is mapped to a functional interface internally. The compiler decides which functional interface it should be mapped to from the context at the time of compiling the source code.

Contrary to other functions in Java, you can define lambda functions that exist outside of the scope of any object. As a result, lambda functions can be called anywhere in the program and passed around. For example, it is possible to pass a lambda function as an argument to another function.

Why do we Need Lambda Expressions?

Java is a high-level programming language that is object-oriented and class-based. This means that, besides the fundamental data types, everything in Java is an object somehow. You cannot define top-level functions in Java; you can’t define a function outside a class. Moreover, Java does not allow you to return a function from another function or pass an argument to another function. Here’s where lambda expressions help.

Read: An Introduction to the Lambda Architecture

Features of Lambda Functions in Java

A lambda expression may contain zero, one, or multiple parameters:

  • You can either explicitly declare the type of parameters or infer it from the context.
  • If you’ve multiple parameters in a lambda expression, you must separate them using commas and wrap them inside a parenthesis.
  • If there are no parameters, i.e., an empty set of parameters, you can represent it by using empty parentheses.
  • If you have a single parameter in a lambda expression, you don’t need parentheses if the type is inferred.
  • The body of the lambda expressions may contain no statements or single or multiple statements.
  • You must use curly brackets if you’ve multiple statements in the body of an expression.
  • There is no point in using curly brackets if there is only one statement in the lambda expression’s body.

What is a Functional Interface in Java?

A functional interface consists of a single abstract method and no other methods. An example of a functional interface is the Runnable interface which is a part of the java.lang package. The Runnable interface contains only one method i.e., the run() method.

Here is how the definition of the Runnable interface looks in C#:

@FunctionalInterface
public interface Runnable {
    public abstract void run();
}

Like the Runnable interface, Comparator is yet another functional interface that contains only one abstract method compare().

Here are a few examples of the functional interfaces newly added in Java 8:

public interface Predicate {
    boolean test(T t);
}
public interface Function<T,R> {
    R apply(T t);
}
public interface BinaryOperator {
    T apply(T left, T right);
}
public interface Consumer {
    void accept(T t);
}
public interface Supplier {
    T get();
}

Read: Understanding Lambda-enabled Design Patterns

Programming Lambda Expressions in Java

Syntax

Here’s the syntax of defining a lambda function:

parameter -> expression

The following statement shows how you can define a lambda expression:

(type arg1, type arg2, type arg3, ...) -> (body)

Note that you do not need to specify the type declaration since the Java compiler is adept at inferring the types of arguments from the context. Here is an example that illustrates this:

(arg1, arg2, arg3, ...) -> (body)

The Lambda Operator in Java

The Java programming language introduces the lambda operator to work with lambda expressions. To create a lambda expression, you have two choices: create your functional interface or leverage a pre-defined functional interface available.

The arrow operator is used to represent lambda expressions in Java. Here is an example that shows this:

(x) -> x * x;

The left side of the arrow operator is used to specify the parameters. This can even be empty, i.e., you can have a lambda expression that has no parameters. The right side of the arrow operator is used to specify the body of the lambda expression.

Read: Java Lambda Expressions Revisited

Java Lambda Expression Code Examples

The following code snippet illustrates a lambda expression that doesn’t accept any parameter:

() -> System.out.println("This is an example of a lambda expression without any parameter");

The following code snippet is an example of a lambda expression with two parameters:

(int x, int y) -> x + y;

Passing Lambda Expressions as Arguments

You can pass lambda expressions as arguments to a function. If you have to pass a lambda expression as a parameter, the parameter type should be able to hold it. If you pass an integer as an argument to a function, you must have an int or Integer parameter. If you are passing an instance of a class as a parameter, you must specify the class name or the object class as a parameter to hold the object.

In Java, there is no type for lambda expression. Instead, it would help if you used an interface, i.e., a functional interface, to accept the parameter.

The following code listing illustrates a lambda expression and a simple functional interface that contains one abstract function and one non-abstract of default function:

interface MyFunctionInterface
{
    void abstractFunction(int x);
      default void nonAbstractFunction()
    {
       System.out.println("Hello World!");
    }
}
public class LambdaExpressionDemo
{
    public static void main(String args[])
    {
        MyFunctionInterface functionObj = (int x) -> System.out.println(x * x);
        functionObj.abstractFunction(5);
    }
}

It should be noted here that adding too many default methods in a functional interface is not a good choice. Here is an example that illustrates how you can pass lambda expression as a parameter to the replaceAll() method.

import java.util.ArrayList;
public class Main {
    public static void main(String[] args) {
        ArrayList cities = new ArrayList<>();
        cities.add("London");
        cities.add("Tokyo");
        cities.add("New York");
        cities.replaceAll(e -> e.toUpperCase());
        System.out.println("Names of cities in UPPER CASE: " + cities);
    }
}

Best Practices for Java Lambda Expressions

Here are some best practices you should adhere to when working with lambda expressions in Java:

  • It is a good practice to use standard functional interfaces
  • You should keep your lambda expressions short
  • Avoid overusing default methods in functional interfaces
  • Avoid specifying parameter types
  • Use lambda expressions to instantiate functional interfaces
  • You should avoid overloading methods that have functional interfaces as parameters

Summary of Lambda Expressions in Java

In Java, lambda expressions are represented as objects, so they need to be associated with a particular object type. This is the target type or the functional interface.

If the target type of the lambda expression and the captured arguments are both serializable, then the lambda expression may be serialized. Serialization of lambda expressions, on the other hand, is highly discouraged, just as it is with inner classes.

The lambda expression was one of the most significant new features of Java 8. It marked the beginning of the transition from object-oriented to functional programming in Java.

Read more Java programming tutorials and guides.

Latest Posts

Related Stories