Java Lambda Expressions

Java Lambda Expressions, introduced in Java 8, provide a clear and concise way to represent one method interface using an expression.

They are particularly useful for functional interfaces, which are interfaces with a single abstract method.

Lambda expressions help simplify code by eliminating the need for anonymous classes, making code more readable and easier to maintain.

Syntax of Lambda Expressions

The syntax of a lambda expression is:

(parameters) -> expression
(parameters) -> { statements; }
  • (parameters): The input parameters for the method.
  • ->: The arrow token separates parameters from the expression or block of code.
  • expression or { statements; }: The body of the lambda expression, which can either be a single expression or a block of statements.

Key Points about Lambda Expressions

  1. Functional Interface Requirement: Lambda expressions can only be used with functional interfaces.
  2. Type Inference: The types of parameters can be inferred by the compiler.
  3. Conciseness: Lambdas simplify code by reducing boilerplate syntax.

Example 1: Basic Lambda Expression with Runnable

The Runnable interface is a functional interface with a single run() method, which is ideal for a lambda expression.

Example

public class LambdaRunnableExample {
    public static void main(String[] args) {
        // Using lambda expression for Runnable
        Runnable task = () -> System.out.println("Task is running");
        
        // Start a thread with the lambda expression
        Thread thread = new Thread(task);
        thread.start();
    }
}

Explanation

  • We create a Runnable using a lambda expression instead of an anonymous inner class.
  • Runnable task = () -> System.out.println(“Task is running”); represents the run() method of Runnable.

Output

Task is running

Example 2: Lambda Expression with Parameters

This example uses a lambda expression with parameters in the Comparator interface to compare two strings by their lengths.

Example

import java.util.Arrays;
import java.util.Comparator;

public class LambdaComparatorExample {
    public static void main(String[] args) {
        String[] names = { "John", "Alice", "Bob", "Charlie" };
        
        // Using lambda expression to sort by string length
        Arrays.sort(names, (s1, s2) -> Integer.compare(s1.length(), s2.length()));
        
        // Display sorted array
        System.out.println(Arrays.toString(names));
    }
}

Explanation

  • (s1, s2) -> Integer.compare(s1.length(), s2.length()) is a lambda expression that implements the compare method of Comparator<String>.
  • This lambda expression sorts strings by their lengths.

Output

[Bob, John, Alice, Charlie]

Example 3: Using Lambda with Custom Functional Interface

You can define your own functional interface to use with lambda expressions.

Example

@FunctionalInterface
interface Greeting {
    void sayHello(String name);
}

public class LambdaCustomInterfaceExample {
    public static void main(String[] args) {
        // Lambda expression for Greeting interface
        Greeting greeting = name -> System.out.println("Hello, " + name + "!");
        
        // Use the lambda expression
        greeting.sayHello("Alice");
        greeting.sayHello("Bob");
    }
}

Explanation

  • Greeting is a custom functional interface with a single method sayHello.
  • name -> System.out.println(“Hello, ” + name + “!”) is a lambda that implements sayHello to greet a user by name.

Output

Hello, Alice!
Hello, Bob!

Example 4: Lambda Expression with Block of Statements

If the lambda body has multiple statements, enclose them in curly braces { }.

Example

@FunctionalInterface
interface MathOperation {
    int operate(int a, int b);
}

public class LambdaBlockExample {
    public static void main(String[] args) {
        // Lambda expression with multiple statements in the body
        MathOperation addition = (a, b) -> {
            System.out.println("Adding " + a + " and " + b);
            return a + b;
        };
        
        int result = addition.operate(5, 3);
        System.out.println("Result: " + result);
    }
}

Explanation

  • (a, b) -> { System.out.println(“Adding ” + a + ” and ” + b); return a + b; } has a block of statements within the lambda.
  • The lambda prints each operand before performing the addition.

Output

Adding 5 and 3
Result: 8

Example 5: Lambda Expressions with Predicate Functional Interface

The Predicate<T> interface is a generic functional interface that accepts a single argument and returns a boolean result. It’s commonly used in filter operations.

Example

import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;

public class LambdaPredicateExample {
    public static void main(String[] args) {
        List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David");

        // Predicate to check if a string starts with "A"
        Predicate<String> startsWithA = s -> s.startsWith("A");

        // Filter and print names starting with "A"
        names.stream()
             .filter(startsWithA)
             .forEach(System.out::println);
    }
}

Explanation

  • Predicate<String> startsWithA = s -> s.startsWith(“A”) checks if a string starts with “A”.
  • filter(startsWithA) filters the stream to include only names that start with “A”.

Output

Alice

Example 6: Using Lambda with Function Interface

The Function<T, R> interface is a functional interface that accepts one argument of type T and returns a result of type R.

Example

import java.util.function.Function;

public class LambdaFunctionExample {
    public static void main(String[] args) {
        // Function to calculate the square of an integer
        Function<Integer, Integer> square = x -> x * x;

        // Use the function
        System.out.println("Square of 5: " + square.apply(5));
        System.out.println("Square of 10: " + square.apply(10));
    }
}

Explanation

  • Function<Integer, Integer> square = x -> x * x; is a lambda that calculates the square of a number.
  • apply is called with the argument to calculate and print the square.

Output

Square of 5: 25
Square of 10: 100

Example 7: Method References with Lambda Expressions

Java provides method references as a shorthand notation for lambdas that call a single method. They are often used to refer to existing methods or constructors.

Example

import java.util.Arrays;
import java.util.List;

public class LambdaMethodReferenceExample {
    public static void main(String[] args) {
        List<String> names = Arrays.asList("Alice", "Bob", "Charlie");

        // Method reference instead of lambda expression
        names.forEach(System.out::println);
    }
}

Explanation

  • System.out::println is a method reference that refers to System.out.println(String).
  • This replaces a lambda that would have called println on each name in the list.

Output

Alice
Bob
Charlie

Example 8: Lambda Expression with BiFunction

The BiFunction<T, U, R> functional interface takes two arguments of types T and U, and returns a result of type R.

Example

import java.util.function.BiFunction;

public class LambdaBiFunctionExample {
    public static void main(String[] args) {
        // BiFunction to concatenate two strings with a space
        BiFunction<String, String, String> concatenate = (s1, s2) -> s1 + " " + s2;

        // Use the BiFunction
        String result = concatenate.apply("Hello", "World");
        System.out.println("Concatenated String: " + result);
    }
}

Explanation

  • (s1, s2) -> s1 + ” ” + s2 is a lambda that concatenates two strings with a space in between.
  • The apply method is called to concatenate “Hello” and “World”.

Output

Concatenated String: Hello World

Summary

Java lambda expressions simplify working with functional interfaces, making code more concise and readable.

Key points include:

  • Syntax: (parameters) -> expression or (parameters) -> { statements }.
  • Functional Interfaces: Lambdas work with interfaces that have a single abstract method.
  • Common Functional Interfaces:
    • Runnable, Comparator, Predicate, Function, BiFunction, etc.
  • Method References: Provide a shorthand for lambdas that only call one method.

Lambda expressions are a core feature for functional programming in Java, making it easier to work with collections, streams, and functional interfaces.

Related posts

Java Base64 encoding and decoding

Java Regular Expressions tutorial with Examples

Understanding JVM Shutdown Hooks tutorial