Java Lambda Expressions


Introduced in Java 8, Lambda Expressions represent a major shift in how Java developers write code. Lambda expressions provide a concise way to express instances of single-method interfaces (functional interfaces) in Java. They allow you to write cleaner and more readable code, especially when working with collections, streams, and event listeners.


What Are Lambda Expressions?

A Lambda Expression is essentially an anonymous method (or function) that can be used to implement methods of functional interfaces (interfaces with a single abstract method). It allows you to pass behavior as a parameter, return behavior from a method, or operate on collections in a more functional style.

Syntax of a Lambda Expression

The syntax of a lambda expression consists of three parts:

  1. Parameters: The input values (optional if no parameters).
  2. Arrow (->): Separates the parameters from the body.
  3. Body: The block of code that is executed (can be a single expression or multiple statements).

The general syntax is as follows:

(parameters) -> expression
// or for multiple statements:
(parameters) -> { statements; }

Example of a Simple Lambda Expression

public class LambdaExample {
    public static void main(String[] args) {
        // Lambda expression that adds two integers
        MathOperation add = (a, b) -> a + b;
        
        System.out.println("Sum: " + add.operation(5, 3));  // Output: Sum: 8
    }
    
    interface MathOperation {
        int operation(int a, int b);
    }
}

Explanation:

  • The lambda expression (a, b) -> a + b implements the method operation of the MathOperation interface.
  • operation takes two integers a and b, and returns their sum.

Types of Lambda Expressions

There are several types of lambda expressions, each serving different purposes:

1. No Parameter Lambda Expression

If a lambda expression takes no parameters, it simply contains a body to perform some action.

Example:

public class NoParameterLambda {
    public static void main(String[] args) {
        // Lambda expression with no parameters
        Greeting greeting = () -> System.out.println("Hello, World!");
        greeting.sayHello();
    }
    
    interface Greeting {
        void sayHello();
    }
}

Explanation:

  • The lambda expression () -> System.out.println("Hello, World!"); is passed to the sayHello() method of the Greeting interface.

2. Single Parameter Lambda Expression

For a single parameter, you can omit the parentheses.

Example:

public class SingleParameterLambda {
    public static void main(String[] args) {
        // Lambda expression with a single parameter
        SquareNumber square = x -> x * x;
        System.out.println("Square of 5: " + square.compute(5));  // Output: Square of 5: 25
    }
    
    interface SquareNumber {
        int compute(int x);
    }
}

Explanation:

  • The lambda expression x -> x * x implements the compute method to calculate the square of a number.

3. Multiple Parameters Lambda Expression

If you have more than one parameter, use parentheses to enclose the parameters.

Example:

public class MultipleParametersLambda {
    public static void main(String[] args) {
        // Lambda expression with multiple parameters
        Calculator calculator = (a, b) -> a + b;
        System.out.println("Sum: " + calculator.add(10, 20));  // Output: Sum: 30
    }
    
    interface Calculator {
        int add(int a, int b);
    }
}

Explanation:

  • The lambda expression (a, b) -> a + b takes two parameters, a and b, and returns their sum.

Advantages of Lambda Expressions

  1. Concise Code: Lambda expressions allow you to write more compact code. They eliminate the need for boilerplate code such as anonymous classes, improving readability.
  2. Improved Readability: Lambda expressions are often more expressive and easier to read than traditional inner classes or anonymous classes, especially when working with functional-style APIs like Streams.
  3. Enable Functional Programming: Java 8 introduced functional programming features with lambda expressions, making it easier to write more declarative and cleaner code when working with collections, streams, or concurrency.
  4. Parallel Processing: Lambda expressions make it easy to perform parallel processing with the Streams API.

Lambda Expressions in Functional Interfaces

Lambda expressions are most commonly used to implement functional interfaces. A functional interface is an interface that has exactly one abstract method. These interfaces are often used as the target type for lambda expressions.

Example with a Functional Interface

@FunctionalInterface
interface Converter {
    int convert(String s);
}

public class LambdaInFunctionalInterface {
    public static void main(String[] args) {
        // Lambda expression implementing the Converter interface
        Converter stringToInt = s -> Integer.parseInt(s);
        System.out.println("Converted number: " + stringToInt.convert("123"));
    }
}

Explanation:

  • The Converter interface has a single abstract method convert(String s). The lambda expression s -> Integer.parseInt(s) implements this method.
  • The lambda expression converts a string to an integer.

Lambda Expressions with Collections and Streams

Lambda expressions are commonly used with Collections and the Streams API to perform operations like filtering, mapping, and reducing.

Example: Using Lambda with forEach in a List

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

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

        // Using lambda expression with forEach to print names
        names.forEach(name -> System.out.println(name));
    }
}

Explanation:

  • The forEach method takes a lambda expression that prints each name in the list.

Example: Using Lambda with Streams

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class LambdaWithStreams {
    public static void main(String[] args) {
        List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9);

        // Using lambda expression with Streams to filter and collect even numbers
        List<Integer> evenNumbers = numbers.stream()
                                           .filter(n -> n % 2 == 0)
                                           .collect(Collectors.toList());
        
        System.out.println("Even numbers: " + evenNumbers);  // Output: [2, 4, 6, 8]
    }
}

Explanation:

  • The filter method uses a lambda expression n -> n % 2 == 0 to filter out odd numbers and retain only the even numbers.

Common Use Cases for Lambda Expressions

Lambda expressions are used widely in Java in the following scenarios:

  1. Event Handlers: Lambda expressions are often used in GUI programming, where event handling (e.g., button clicks) can be handled more concisely.
  2. Threading: Lambda expressions are useful in multi-threading and concurrency, particularly with the Runnable interface.
  3. Functional Interfaces: As shown earlier, lambda expressions are used extensively to implement functional interfaces.