Lambda Expressions in Java: Explained in Easy Steps

Lambda Expressions in Java: Explained in Easy Steps

10 Sep 2024
Beginner
388 Views
36 min read

Lambda Expression in Java

Lambda Expression in Java is a new and important feature of Java that was included in Java SE 8It provides a clear and concise way to represent one method interface using an expression. It is very useful in the Java collection library. It helps to iterate, filter, and extract data from the collection. The Lambda expression is used to implement a functional interface.

In the Java tutorial, we will learn what is lambda expression in Java?, the syntax of lambda expressions,understand functional interfaces, types of lambda expressions in Java, lambdas vs method references, anonymous classes vs lambda expression, lambdas vs streams API, lambdas vs method references, and many more.

What is Lambda Expression in Java?

Lambda Expressions in Java are specific sections of code that function like standard methods. They take in a collection of parameters and provide a value as the result. In contrast to methods, a lambda expression does not always need a name. It saves a lot of code. In the case of the lambda expression, we don't need to define the method again to provide the implementation.

  • Lambda expressions were introduced to provide a clear and concise way to represent one method interface using an expression.
  • Allows for more readable and compact code by eliminating the need for anonymous classes.
  • Works with interfaces that have a single abstract method (e.g., Runnable, Comparator).
  • Often used with the Streams API for filtering, mapping, and iterating over collections.
  • Makes code more concise and easier to understand, especially in operations involving collections.
  • The type of parameters can be inferred, so you don’t always need to specify them explicitly.
Read More:
What is Java? A Beginner Guide to Java
Java Developer Salary Guide in India – For Freshers & Experienced
Lambda Function in Python with Examples (Full Tutorial)

Syntax of Lambda Expression in Java

(argument-list) -> {body}

1. Syntax for the Zero Parameter

() -> System.out.println("Zero parameter lambda");

2. Syntax for the One Parameter

(p) -> System.out.println("One parameter: " + p);

3. Syntax for the Multiple Parameter

(p1, p2) -> System.out.println("Multiple parameters: " + p1 + ", " + p2);

Expression in Java consists of three components:

  • Argument list: It can be empty or non-empty as well.
  • Arrow-token: It is used to link the arguments list and body of expression.
  • Body: It contains expressions and statements for lambda expression.

Syntax of Lambda Expression in Java

What is Functional Interfaces?

Functional interface in Java is an interface with just one abstract method on it. The contract that the lambda expression or method reference will satisfy is defined by this one abstract method. In Java, lambda expressions and method references are used primarily with functional interfaces in mind.

Key points to be remembered for the Functional Interface:

  • A functional interface must have only one abstract method. This method is called the functional method.
  • Using the @FunctionalInterface annotation is a best practice to ensure the interface has only one abstract method, as it enforces this rule at compile-time.
  • A functional interface can have any number of default or static methods as long as it has only one abstract method.

Example: Functional Interface

@FunctionalInterface
interface ScholarHat {
    void learn(); // Single abstract method
}

Example: Using Functional Interface in Lambda Expression

@FunctionalInterface
interface ScholarHat {
    void study(); // Single abstract method
}

public class LambdaExample {
    public static void main(String[] args) {
        // Using a lambda expression to implement the ScholarHat interface
        ScholarHat learningSession = () -> System.out.println("Studying with ScholarHat!");
        learningSession.study();  // Output: Studying with ScholarHat!
    }
}

Output

Studying with ScholarHat!
Read More:
Java Full Stack Developer Roadmap for Beginners (Updated 2024)
Top 10 Reasons to Know Why Java is Important?

Types of Lambda Expression in Java

1. Lambda Expression in Java with Zero Parameter

A lambda expression with no parameters directly provides an implementation for the functional interface's method.

Example

@FunctionalInterface
interface Greet {
    // Single abstract method for the functional interface
    void sayHello();
}

public class LambdaExample {
    public static void main(String[] args) {
        // Lambda expression implementing the sayHello method of the Greet interface
        Greet greeting = () -> System.out.println("Hello, World!");
        
        // Calling the sayHello method, which executes the lambda expression
        greeting.sayHello(); 
    }
}

Output

Hello, World!

2. Lambda Expression in Java with Single Parameter

A lambda expression with one parameter doesn't need parentheses around the parameter.

Example

@FunctionalInterface
interface Square {
    // Single abstract method that takes an integer and returns its square
    int calculate(int x);
}

public class LambdaExample {
    public static void main(String[] args) {
        // Lambda expression implementing the calculate method of the Square interface
        Square square = x -> x * x;
        
        // Calling the calculate method with the argument 5, which computes 5 * 5
        System.out.println(square.calculate(5));  
    }
}

Output

25

3. Lambda Expression in Java with Multiple Parameters

A lambda expression with multiple parameters requires parentheses around the parameters.

Example

@FunctionalInterface
interface Add {
    // Single abstract method that takes two integers and returns their sum
    int sum(int a, int b);
}

public class LambdaExample {
    public static void main(String[] args) {
        // Lambda expression implementing the sum method of the Add interface
        Add addition = (a, b) -> a + b;
        
        // Calling the sum method with arguments 10 and 20, which computes 10 + 20
        System.out.println(addition.sum(10, 20));
    }
}

Output

30

4. Lambda Expression in Java with Block of Code

A lambda expression with a block of code requires curly braces and a return statement if there is a return value.

Example

@FunctionalInterface
interface Multiply {
    // Single abstract method that takes two integers and returns their product
    int multiply(int a, int b);
}

public class LambdaExample {
    public static void main(String[] args) {
        // Lambda expression implementing the multiply method of the Multiply interface
        Multiply multiplication = (a, b) -> {
            // Calculate the product of a and b
            int result = a * b;
            // Return the result
            return result;
        };
        
        // Calling the multiply method with arguments 4 and 5, which computes 4 * 5
        System.out.println(multiplication.multiply(4, 5)); 
    }
}

Output

20

5. Lambda Expression in Java with Method Reference

While not a lambda expression per se, method references provide a shorthand way to write lambdas that call a specific method.

Example

@FunctionalInterface
interface Printer {
    // Single abstract method that takes a String message and prints it
    void print(String message);
}

public class LambdaExample {
    public static void main(String[] args) {
        // Method reference to System.out.println, 
        //implementing the print method of the Printer interface
        Printer printer = System.out::println;
        
        // Calling the print method with the message "Hello, Method Reference!"
        printer.print("Hello, Method Reference!");  // Output: Hello, Method Reference!
    }
}

Output

Hello, Method Reference!

Examples of Lambda Expressions in Java

Here are some of the most important examples that will help you to understand Lambda Expression in Java properly:

1. Without Using Lambda Expression

@FunctionalInterface
interface Greet {
    void sayHello();
}

public class ScholarHat {
    public static void main(String[] args) {
        // Implementing the Greet interface using an anonymous class
        Greet greeting = new Greet() {
            @Override
            public void sayHello() {
                System.out.println("Hello from ScholarHat!");
            }
        };
        
        // Calling the sayHello method
        greeting.sayHello();
    }
}

Output

Hello from ScholarHat!

2. By Using Lambda Expression

@FunctionalInterface
interface Greet {
    // Single abstract method to be implemented
    void sayHello();
}

public class ScholarHat {
    public static void main(String[] args) {
        // Implement the Greet interface using a lambda expression
        Greet greeting = () -> System.out.println("Hello from ScholarHat!");
        
        // Call the sayHello method of the Greet instance
        greeting.sayHello();
    }
} 

Output

Hello from ScholarHat!

3. Iterating Collections Using the Foreach Loop

In Java, the forEach method of the Collection interface can be used to iterate over collections with the help of lambda expressions. This approach is both concise and readable. Here’s how you can use the forEach method along with lambda expressions to iterate over a collection.

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

public class ScholarHat {
    public static void main(String[] args) {
        // Define a list of strings
        List names = Arrays.asList("Aman", "Bhanu", "Charu", "Dev");
        
        // Iterate over the list using forEach and a lambda expression
        names.forEach(name -> System.out.println(name));
    }
}

Output

Aman
Bhanu
Charu
Dev
Read More:
for Loop in Java: Its Types and Examples
while Loop in Java
do...while Loop in Java - Flowchart & Syntax (With Examples)

4. Java Lambda Expression With or Without Return Keyword

1. Lambda Expression Without 'return' Keyword

When a lambda expression has a single expression, you can omit the return keyword. This is known as an expression lambda.


@FunctionalInterface
interface Square {
    int calculate(int x);
}

public class LambdaExample {
    public static void main(String[] args) {
        // Lambda expression without return keyword
        Square square = x -> x * x;
        
        // Calling the calculate method
        System.out.println(square.calculate(5));  // Output: 25
    }
}

Output

25

2. Lambda Expression With return Keyword

When a lambda expression contains multiple statements, you need to use curly braces {} and include the return keyword to specify the return value.

@FunctionalInterface
interface Square {
    int calculate(int x);
}

public class LambdaExample {
    public static void main(String[] args) {
        // Lambda expression with return keyword
        Square square = x -> {
            int result = x * x;
            return result;
        };
        
        // Calling the calculate method
        System.out.println(square.calculate(5));
    }
}

Output

25

5. Java Lambda Expression - Creating Thread

Lambda expressions in Java streamline thread creation by directly implementing the Runnable interface, making code more concise and readable. Before Java 8, thread creation required defining a new class or extending the Thread class.

public class LambdaThreadExample {
    public static void main(String[] args) {
        // Creating a thread using a lambda expression
        Thread thread = new Thread(() -> {
            for (int i = 0; i < 5; i++) {
                System.out.println("Running in thread: " + Thread.currentThread().getName() + ", Count: " + i);
                try {
                    Thread.sleep(500); // Sleep for 500 milliseconds
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        
        // Start the thread
        thread.start();
        
        // Main thread output
        for (int i = 0; i < 5; i++) {
            System.out.println("Running in main thread: " + Thread.currentThread().getName() + ", Count: " + i);
            try {
                Thread.sleep(500); // Sleep for 500 milliseconds
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

Output

Running in thread: Thread-0, Count: 0
Running in main thread: main, Count: 0
Running in thread: Thread-0, Count: 1
Running in main thread: main, Count: 1
Running in thread: Thread-0, Count: 2
Running in main thread: main, Count: 2
Running in thread: Thread-0, Count: 3
Running in main thread: main, Count: 3
Running in thread: Thread-0, Count: 4
Running in main thread: main, Count: 4

6. Java Lambda Expression - Comparator

Lambda expressions simplify the implementation of the Comparator interface for sorting collections, making the code more concise and readable. Before Java 8, comparators were required to define new classes or anonymous classes.

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

public class LambdaComparatorExample {
    public static void main(String[] args) {
        // Define a list of strings
        List names = Arrays.asList("Aman", "Ankita", "Raghav", "Prince");
        
        // Sort the list in natural order using a lambda expression
        names.sort((s1, s2) -> s1.compareTo(s2));
        
        // Print the sorted list
        System.out.println("Sorted names: " + names);
    }
}

Output

Sorted names: [Aman, Ankita, Prince, Raghav]

7. Java Lambda Expression - Filter Collection Data

Lambda expressions in Java can be used to filter data in collections, making it easier to process and manipulate data. The Stream API, introduced in Java 8, provides methods like filters that work seamlessly with lambda expressions for filtering data.

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

public class LambdaFilterExample {
    public static void main(String[] args) {
        // Define a list of strings
        List names = Arrays.asList("Aman", "Ankita", "Radha", "Price", "Abhishek");

        // Filter the list to include only names that start with "A"
        List filteredNames = names.stream()
                                          .filter(name -> name.startsWith("A"))
                                          .collect(Collectors.toList());

        // Print the filtered list
        System.out.println("Filtered names: " + filteredNames);
    }
}

Output

Filtered names: [Aman, Ankita, Abhishek]

8. Java Lambda Expression - Event Listener

Lambda expressions in Java can be used to simplify the implementation of event listeners, making your code more concise and readable. This is especially useful in GUI programming with Swing or JavaFX, where event handling is common.

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

public class LambdaEventListenerSwing {
    public static void main(String[] args) {
        // Create the JFrame
        JFrame frame = new JFrame("Lambda Event Listener Example");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(300, 200);

        // Create a JPanel
        JPanel panel = new JPanel();

        // Create a JButton
        JButton button = new JButton("Click Me!");

        // Add ActionListener using lambda expression
        button.addActionListener(event -> System.out.println("Button clicked!"));

        // Add button to panel
        panel.add(button);

        // Add panel to frame
        frame.add(panel);

        // Make the frame visible
        frame.setVisible(true);
    }
}

Comparing Lambda Expressions with Other Functional Constructs

Lambda Expression in Java provides an easy approach to defining single-method interface (or functional interface) instances. However, there are a number of additional functional constructs in Java that have unique uses.

1.  Anonymous Classes vs Lambda Expressions

This is the comparison of Java's anonymous classes and lambda expressions:

FactorsAnonymous Classes Lambda Expressions
Syntaxnew Interface() { @Override method() { } } parameters -> expression or parameters -> { statements }
Use-casesImplement interfaces or extend classes Implement functional interfaces (single-method interfaces)
ReadabilityMore verbose and boilerplate code More concise and readable
Constructor InvocationCan have constructors and instance initializers It cannot have constructors; only method implementations
Access to 'this'Refers to the instance of the anonymous class Refers to the enclosing class's instance
ScopeHas its scope; can access enclosing class members Inherits scope from the enclosing method/class
TypeCreates a new class at runtime Directly uses the target functional interface
When to Use Use it when you need to extend a class, implement multiple methods, or need more complex logic.Use for simple implementations of functional interfaces where a single method needs to be implemented.
Method Access Can access methods and fields of the enclosing class Limited to what’s in scope; no direct access to this methods.

2. Lambdas vs Streams API

FactorsLambda ExpressionStreams API
PurposeTo provide a concise syntax for implementing functional interfaces. To process sequences of elements (collections) in a declarative way.
Syntaxparameters -> expression or parameters -> { statements }  collection.stream().operation(...)
Use CaseImplement functional interfaces such as Runnable, Comparator, etc. Perform operations on collections like filter, map, reduce, etc.
ReadabilityImproves readability by reducing boilerplate code for single-method interfaces. Improves readability by allowing for a more declarative approach to processing collections.
Scope Primarily used within the context of functional interfaces. Used with collections, arrays, or other data sources that can be converted to a stream.
PerformanceDirect method implementation, generally efficient. It can be optimized by the JVM and supports parallel processing for better performance on large datasets.
State Management Stateless; each lambda expression typically represents a single, isolated operation. Stateless by default, but can be stateful in cases like distinct() or sorted().
OperationsLimited to the operations defined in the functional interface. Supports a wide range of operations like filter, map, flatMap, collect, reduce, etc.
When to Use Use when you need to implement a functional interface, particularly for short, simple tasks. Use when you need to process collections in a declarative, functional style, especially with multiple operations or parallel processing.

3. Lambdas vs Method References

FactorsLambda ExpressionMethod Reference
PurposeProvides a concise way to implement functional interfaces inline. A shorthand for calling an existing method in a lambda expression.
Syntaxparameters -> expression or parameters -> { statements } ClassName :: methodName or object :: methodName
Use CaseUsed when custom logic needs to be written inline. Used when an existing method can be referenced directly.
ReadabilityMore flexible but can be slightly verbose for simple operations. More concise and readable, especially when referencing simple methods.
When to useUse when you need to write inline logic or call methods with parameters. Use when you are calling an existing method, simplifying the code.
FlexibilityMore flexible; allows writing custom code within the lambda body. Less flexible; can only be used to reference existing methods.
Constructor Support No direct support for constructors; must call them explicitly. Less flexible; can only be used to reference existing methods.
ChainingCan be used in chaining (e.g., in stream operations). Can also be used in chaining, often improving readability.
Performance Performance is similar to method references but might include extra overhead. Slightly better performance as it’s a direct method reference.
Conclusion

In conclusion, we have explored Lambda expressions in Java, which simplify the implementation of functional interfaces and reduce boilerplate code. They enhance code readability, making it easier to work with collections and functional operations like filtering and mapping. Lambda expressions are now a key tool for writing cleaner, more efficient Java code. If you are a newbie to Java Programming, we recommend you to enroll in our Java Full Stack Course to get a better understanding with a step-by-step comprehensive guide to Full Stack Java Development.

FAQs

Lambda expressions in Java are a powerful feature that simplifies the syntax for implementing functional interfaces. However, they come with some limitations: 
  • No state management (stateless).
  • Only works with functional interfaces (one abstract method).
  • Limited to simple expressions or blocks of code.
  • Difficult to debug due to concise syntax.
  • Type inference can be ambiguous in complex cases.

Yes, lambda expressions can throw exceptions, but they must be handled within the lambda or be declared in the method signature if it's a checked exception. Unchecked exceptions don't need explicit handling.

No, lambda expressions can only be used with functional interfaces that have a single abstract method. 

Yes, lambda expressions are stateless and can only capture effectively final variables from the outer scope. 
Share Article
About Author
Shailendra Chauhan (Microsoft MVP, Founder & CEO at Scholarhat by DotNetTricks)

Shailendra Chauhan is the Founder and CEO at ScholarHat by DotNetTricks which is a brand when it comes to e-Learning. He provides training and consultation over an array of technologies like Cloud, .NET, Angular, React, Node, Microservices, Containers and Mobile Apps development. He has been awarded Microsoft MVP 9th time in a row (2016-2024). He has changed many lives with his writings and unique training programs. He has a number of most sought-after books to his name which has helped job aspirants in cracking tough interviews with ease.
Accept cookies & close this