Java 8 Lambda Expressions and Functional Interfaces
Tags: java, java8, lambda, functionalinterfaces
Published: 2024-06-09 14:01:39

**Overview :**

Java 8 introduced Lambda Expressions and Functional Interfaces, which bring functional programming capabilities to Java. These features allow for more concise and readable code, especially when working with collections and performing common tasks like filtering, mapping, and reducing

By the end of this blog, we will understand:

**What Lambda Expressions are?
What Functional Interfaces are?
How to create and use Lambda Expressions?
Common use cases for Lambda Expressions and Functional Interfaces**

**What are Lambda Expressions?**
Lambda Expressions are a way to provide clear and concise syntax for writing anonymous methods (functions). They enable you to treat functionality as a method argument, or pass a block of code around as data

**Syntax of Lambda Expressions :**
The basic syntax of a lambda expression is:

```
(parameters) -> expression
or
(parameters) -> { statements; }
```
**Example: Simple Lambda Expression**

```
// Traditional way using an anonymous class
Runnable runnable = new Runnable() {
    @Override
    public void run() {
        System.out.println("Hello, world!");
    }
};

// Using a lambda expression
Runnable lambdaRunnable = () -> System.out.println("Hello, world!");

```
**What are Functional Interfaces?**
A Functional Interface is an interface with a single abstract method. They can have multiple default or static methods but only one abstract method. Lambda expressions can be used to instantiate functional interfaces.

**Example: Defining a Functional Interface**

```
@FunctionalInterface
public interface MyFunctionalInterface {
    void myMethod();
}

```
Java 8 includes several built-in functional interfaces in the java.util.function package, such as Predicate, Function, Consumer, and Supplier.

**Creating and Using Lambda Expressions :**

**Example 1: Using Predicate Interface**
The Predicate interface represents a boolean-valued function of one argument.

```
import java.util.function.Predicate;

public class Main {
    public static void main(String[] args) {
        Predicate<String> isEmpty = (str) -> str.isEmpty();
        
        System.out.println(isEmpty.test("")); // Output: true
        System.out.println(isEmpty.test("Hello")); // Output: false
    }
}

```
**Example 2: Using Function Interface**
The Function interface represents a function that takes one argument and produces a result.

```
import java.util.function.Function;

public class Main {
    public static void main(String[] args) {
        Function<Integer, String> intToString = (num) -> "Number: " + num;
        
        System.out.println(intToString.apply(5)); // Output: Number: 5
    }
}

```
**Example 3: Using Consumer Interface**
The Consumer interface represents an operation that takes a single argument and returns no result.

```
import java.util.function.Consumer;

public class Main {
    public static void main(String[] args) {
        Consumer<String> printUpperCase = (str) -> System.out.println(str.toUpperCase());
        
        printUpperCase.accept("hello"); // Output: HELLO
    }
}

```
**Example 4: Using Supplier Interface**
The Supplier interface represents a supplier of results, which doesn't take any arguments and returns a result.
import java.util.function.Supplier;

```
public class Main {
    public static void main(String[] args) {
        Supplier<String> helloSupplier = () -> "Hello, world!";
        
        System.out.println(helloSupplier.get()); // Output: Hello, world!
    }
}
```
**Common Use Cases for Lambda Expressions and Functional Interfaces :**


**Use Case 1: Filtering Collections**

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

public class Main {
    public static void main(String[] args) {
        List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David");
        
        // Filter names that start with 'A'
        List<String> filteredNames = names.stream()
          .filter(name -> name.startsWith("A"))
              .collect(Collectors.toList());
        
        filteredNames.forEach(System.out::println);             // Output: Alice
    }
}

```
**Use Case 2: Mapping Collections**

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

public class Main {
    public static void main(String[] args) {
        List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David");
        
        // Convert names to uppercase
        List<String> upperCaseNames = names.stream()
                                           .map(String::toUpperCase)
                                           .collect(Collectors.toList());
        
        upperCaseNames.forEach(System.out::println); // Output: ALICE, BOB, CHARLIE, DAVID
    }
}

```

**Use Case 3: Reducing Collections**

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

public class Main {
    public static void main(String[] args) {
        List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
        
        // Sum of all numbers
        int sum = numbers.stream()
                         .reduce(0, Integer::sum);
        
        System.out.println("Sum: " + sum); // Output: Sum: 15
    }
}

```
**Use Case 4: Creating Custom Functional Interfaces**

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

public class Main {
    public static void main(String[] args) {
        // Define lambda expressions for addition and multiplication
        MathOperation addition = (a, b) -> a + b;
        MathOperation multiplication = (a, b) -> a * b;
        
        System.out.println("Addition: " + addition.operate(5, 3)); // Output: Addition: 8
        System.out.println("Multiplication: " + multiplication.operate(5, 3)); // Output: Multiplication: 15
    }
}

```
**Summary**
Lambda Expressions and Functional Interfaces are powerful features in Java 8 that enable you to write more concise, readable, and functional-style code. They are particularly useful for operations on collections and data, allowing you to:

**Filter:** Select elements based on a condition.
**Map:** Transform elements.
**Reduce:** Combine elements into a single result.
**Custom Functional Interfaces:** Define your own interfaces for specific tasks

**Happy Coding...**