The Ultimate Guide to Lambda Expressions in Java

The Ultimate Guide to Lambda Expressions in Java

<strong>Originally published </strong><em>at&nbsp;</em><a href="https://www.stackchief.com/tutorials/The%20Ultimate%20Guide%20to%20Lambda%20Expressions%20in%20Java" target="_blank">stackchief.com<em>&nbsp;</em></a><em>on&nbsp;February 15, 2019</em>

Originally published at stackchief.com on February 15, 2019

Lambda expressions are functions that can be passed around as arguments. Using lambdas, you can create "anonymous methods" that implement functional interfaces with a more concise syntax. Lambdas have become increasingly popular with the movement towards more functionalprogramming.

In this tutorial, we'll cover everything you need to know about lambdas. We'll explain what lambdas are, how they originated, and how they improve upon things like anonymous classes and functional interfaces. We'll explore best use cases and provide examples of using lambda expressions in various contexts.


What are lambdas in Java?

Lambda expressions are functions as arguments. They provide a more convenient syntax for implementing a functional interface as demonstrated below:

interface  Print {
    void print(String message);
}

public class MainClass {
    public static void main(String args[]) {
        Print myPrinter = x -> System.out.println(x);
        myPrinter.print("Hello lambdas!");
    }
}

Notice how we first define an interface Print that defines exactly one abstract method. Any interface that defines exactly one abstract method is a functional interface.

We use a lambda expression x -> System.out.println(x) to implement this single abstract method in a more concise way.

Lambdas provide a clear and concise way of representing a functional interface. Lambdas can also be considered "anonymous functions" and can be passed around as arguments to other functions:

interface  MathOp {
    int operate(int a, int b);
}

public class MainClass {
    public static void printResults(int x) {
        System.out.println(x);
    }

    public static void main(String args[]) {
        MathOp add = (a, b) -> {
            return a + b;
        };
        printResults(add.operate(2, 2));
        //prints 4
    }
}

Notice how we first define a functional interface MathOp that defines a single operate method returning an integer.

We define a lambda expression add which implements the MathOp interface. Notice how this expression takes two parameters (a, b) and returns the added result a + b.

We can then pass our lambda expression add into our separate printResults() method. We can do this because our lambda expression evaluates to the target data type int accepted by the printResults() method.


Lambda Syntax

Lambda expressions consist of three entities:

(a, b) -> {}

1) Argument List (a,b)

The argument list is a comma-separated list of parameters enclosed in parentheses. These arguments usually don't require type declarations as their types can be inferred by the compiler. The parentheses () are optional if you only have a single argument.

2) Arrow token ->

This is the syntax for lambda expressions and signifies the passing of the parameters to the body.

3) Body {}

The body is a code block that represents the implementation of a functional interface. If the body is a single statement, the expression will evaluate and return the result. In this case, the brackets {} are optional. If the body is more than a single statement, you must use brackets and return the result.


Why use lambdas in Java?

A more concise syntax

Lambda expressions allow you to implement a functional interface with fewer lines of code than an anonymous class. Working off our previous example, let's also implement the same Print interface using a nested class:

interface  Print {
    void print(String message);
}

public class MainClass {
    public static void main(String args[]) {
        //using nested class
        Print myNestedPrinter = new Print(){
            public void print(String x) {
                System.out.println(x);
            }
        };
        //using lambda
        Print myPrinter = x -> System.out.println(x);

        myNestedPrinter.print("Hello nested classes");
        myPrinter.print("Hello lambdas!");
    }
}

This example demonstrates the benefit of using a lambda over an anonymous class. With the anonymous class, we have to explicitly create a new instance of the Print interface and implement its print method. This takes 4 more lines of code than using using a lambda expression.


Lambdas make it easier to work with collections

Lambdas provide a much more elegant way of working with collections. For example:

import java.util.*;
public class MainClass {
    public static void main(String args[]) {
        List<Character> list = new ArrayList<Character>();
        list.add('a');
        list.add('b');
        list.add('c');
        list.forEach(x -> System.out.println(x));
    }
}

Using the forEach method, we define a lambda expression x -> System.out.println(x) that is applied to every element in the collection.

This is considered an internal iteration and can have some performance implications when used with the Streams API. More specifically, parallel processing can be easily implemented with internal iterations as they offload the management of the iteration to a process. This is different from external iterations which fully manage how the iteration is implemented.

While the differences between internal and external iterators are outside the scope of this article, Dhruv Rai Puri's Java 8 Internal Iterators vs External Iterators explains these differences in greater detail.


Method References

When a lambda expression simply calls an existing method you can use a method referenceinstead.

interface Print {
    void print(String msg);
}

public class MainClass {
    public static void systemPrint(String x) {
        System.out.println(x);
    }

    public static void main(String args[]) {
        Print lambdaPrint = x -> System.out.println(x);
        Print methodPrint = MainClass::systemPrint;
        Print objectPrint = System.out::println;

        lambdaPrint.print("printing with a lambda expression!");
        //prints printing with a lambda expression!
        methodPrint.print("printing with a static method reference");
        //prints printing with a static method reference
        objectPrint.print("printing with an object method reference");
        //prints printing with an object method reference
    }
}

In our example above, notice how lambdaPrint is set to a lambda expression x -> System.out.println(x). This expression is equivalent to the method reference MainClass::systemPrint used on the next line. This is considered a reference to a static method

We also reference an instance method of a particular object on the next line System.out::println. It turns out there are four different kinds of method references:

  • reference to a static method
  • reference to an instance method of a particular object
  • reference to an instance method of an arbitrary object of a particular type
  • reference to a constructor

The general syntax for a method reference is:

Object :: method

With a method reference, you generally don't need to worry about passing arguments. In the above example, the compiler can infer the arguments based on the static method definition for systemPrint().

While the different types of method references have a similar syntax, there are some subtle differences in how they handle arguments, etc. If you want to dig further, Esteban Herrera does a great job of explaining these differences in his article Java 8 Method Reference: How to Use It.


The java.util.function package

Lambda expressions implement functional interfaces. You can't use a lambda expression without referencing an existing functional interface. This is why all of the examples you see in this tutorial first define a functional interface.

It can't get rather tedious creating functional interfaces for every method you want to implement as a lambda expression. For these reasons, Java provides a set of reusable, generic, functional interfaces that are ready for use out of the box:

import java.util.function.Consumer;
public class MainClass {
    public static void main(String args[]) {
        String message = "Hello world!";
        Consumer<String> myConsumer = x -> System.out.println(x);
        myConsumer.accept(message);
        //prints Hello world!
    }
}

In this example, notice how we first import the java.util.function.Consumer interface. The Consumer is a generic interface that accepts one argument and returns no result. This is perfect for situations where you want to log a message because you aren't returning a value but performing an action on a single message argument.

While we could have defined our own interface to achieve the same results, we save ourself time by using a predefined functional interface in the java.util.function package.

Notice how we call the accept() method as defined in the Consumer interface.

Before creating your own functional interface, be sure to check the java.util.function package for existing generic functional interfaces you can use in your code.


Lambdas are lexically scoped

Lambdas are lexically scoped, meaning they don't inherit any names from supertypes or introduce new level of scoping. For these reasons, lambdas don't have the same shadowing issues experienced with nested classes. Baeldung does a great job of explaining this concept in his Lambda Tips and Best Practices article.

Remember that lambdas can access any local variables in their enclosing scope as long as they are final or effectively final. This is a fancy term for saying a value isn't reassigned:

interface Print {
    void print();
}

public class MainClass {
    public static void main(String args[]) {
        String message = "Hello world!";
        message = "new message";
        Print myPrinter = () -> {
            System.out.println(message);
            //compile time error as message has been reassigned
        };
        myPrinter.print();
    }
}

This example results in a compile time error because we reassign the message variable. If we hadn't reassigned message, we could reference the variable directly in our lambda expression as it would be considered effectively final.


Conclusion

Lambdas are key to achieving a more functional approach to programming in Java. They provide a more elegant way of implementing functional interfaces and allow you to pass around anonymous methods as regular arguments.

Still confused? Check out Luis Santiago's intro to working with Lambda expressions in Java. This provides a high level introduction with some good examples for getting started.

If you are craving more, check out Lambda Expressions in Java 8 and Lambda and Streams in Java 8. These are a bit dated but are written by reputable authors who know what they are talking about.

----------------------------------------------------------------------

Thanks for reading :heart: If you liked this post, share it with all of your programming buddies! Follow me on Facebook | Twitter

Learn More

☞ Java Programming Masterclass for Software Developers

☞ Selenium WebDriver with Java -Basics to Advanced+Frameworks

☞ Java In-Depth: Become a Complete Java Engineer!

☞ JSP, Servlets and JDBC for Beginners: Build a Database App

☞ JSP, Servlet, JSLT + Hibernate: A complete guide

☞ Java Hibernate Tutorial for Beginners

☞ 50+ Java Interview Questions for Programmers

☞ Top 5 Java Test Frameworks for Automation in 2019

☞ Spring Boot + JPA + Hibernate + Oracle

☞ Functional programming for Java developers

Java Fundamentals: Learn Java for absolute beginners |Simpliv

Java Fundamentals: Learn Java for absolute beginners |Simpliv

Java Fundamentals: Learn Java for absolute beginners

Description
This is the best course to learn to program in Java in Spanish from scratch and without any experience in this fabulous programming language. This is the first course where we will study the Fundamentals of Java, and we will take you step by step until you acquire the bases of the Java language and you can start to study more advanced Java topics.

The content is divided into perfectly structured levels, each level supported by the previous one, with the aim of adding Java knowledge incrementally and so you can focus on mastering the issues little by little and gradually. So ensure the success of your Java training.

We will also offer support for any doubts about the didactic material included in this Java Fundamentals course.

We manage a new teaching methodology that we have called Speed ​​Learning. This methodology consists of concise videos that go directly to the point to be studied, complemented by eBooks with explanations and step-by-step images (which you can print, or search for any text you need, or use for your offline study), since As we know we can not do text search within a video. In addition, our methodology includes perfectly structured and very didactic exercises that will allow you to accelerate your eLearning learning. No loss of time in videos where you have to watch the instructor codify an exercise, too much theory, little practice or anything like that. Our Speed ​​Learning methodology guarantees that in the shortest possible time you will acquire the necessary knowledge for the Java professional and working world.

The Java Fundamentals course includes the following topics for study:

Lesson 1 - Starting with Java Technology

The amazing world of Java programming

What is Java technology (from a practical approach)

Our first Java program from scratch

Lesson 2 - Variables and Operators in Java

Use of Variables in Java and what we use them for

Types of Data in Java and how they are classified

Management and Classification of operators in Java

Lesson 3 - Control statements in Java

Using the if-else structure and where to use it

Handling the switch structure and when applying it

Lesson 4 - Handling Loops in Java

Use of the for loop and its use

Using the while loop and how to apply it

Use of the do-while loop and when to use it

Lesson 5 - Object Oriented Programming

Introduction to Object Oriented Programming (OOP)

Handling Classes in Java

Use of Objects in Java

Lesson 6 - Functions in Java

Declaration of Methods or Functions in Java

Use and call of functions in Java

Lesson 7 - Data Management in Java

Using Arrays in Java

Management of Matrices in Java

Lesson 8 - Inheritance in Java

Inheritance Management in Java

Use of superclasses and subclasses in Java

Final Level Laboratory

Final Exercise where everything learned in this Level is integrated

At the end you get a certificate of having completed the Java Fundamentals course.

We wait for you on the other side.

Ing. Ubaldo Acosta

Founder of Global Mentoring

Passion for Java Technology

Who this course is for:

Anyone who wants to learn how to program in Java
Basic knowledge
Basic knowledge of PC use
Basic management of an operating system such as Windows, Mac or Linux
It is not necessary to know how to program, we will start from scratch !!!
The attitude and desire to start coding and learning Java once and for all from scratch!
What will you learn
Have the basics of the programming language with Java
You will know the basic syntax of the Java language
Manage the concept of Variables and Operators in Java
We will study Object Oriented Programming with Java
You will learn the Control Statements and Loops in Java
We will see the concept of Functions with Java
We will study the concept of Inheritance in Java
We will learn to use Arrays in java
We will handle the concept of Matrices in Java
We will learn to Design Classes in Java
We will make a final application with everything learned in the course
To know more:

Java Essentials : Learn Core Java From Basic to Advance

Java Essentials : Learn Core Java From Basic to Advance

Learn Java Programming Using Practical Assignments. Start Building Back-end Web Applications Robust Test Automation Frameworks By End Of The Course. Learn More!

Description
This is only Java related course and it's great because it covers just the right amount of Java which is needed to leaning programming, java.

This is a comprehensive yet simple course on java programming language and it concentrates on Java programming concepts.

*************************** No Prior Coding Experience Needed ***************************

This course assumes that you have no programming background. If you have some experience then, it's just a bonus point. You have never code, have some experience or have a lot of experience any other programming language, this course is one stop place for you.

Java is one of the most and useful programming languages to learn You can build back-end of web applications and build robust test automation framework. Specially for Selenium WebDriver GUI automation, Java is most popular choice and has the largest community.

Each lecture consist of a video screencast and code files

There are quizzes, homework to test your knowledge

High focus on practice and asking questions

You will also learn coding best practices

Market is never short of jobs in Java programming language, there are ample of jobs in both Java development and Automation Testing using Java.

What are you waiting for? Enroll today and learn the powerful Java language !!!

Basic knowledge
Nothing else! It’s just you, your computer and your hunger to get started today
Java concepts are covered in the course, no experience needed
Windows/MAC computer
What will you learn
You will be able to EXPLAIN, DESIGN and IMPLEMENT efficient java Programs
You will be confident to clear test automation interviews
Understand the concepts of Object Oriented Programming Language
Complete understanding of java
Expert-level knowledge of Java code (+ advanced tips and tricks used by the pros)
Suitable for beginner programmers and ideal for users who learn faster when shown
To learn more:

Fundamentos de Java: Aprende Java desde cero, sin misterios | Simpliv

Fundamentos de Java: Aprende Java desde cero, sin misterios | Simpliv

Fundamentos de Java: Aprende Java desde cero, sin misterios

Description
This is the best course to learn to program in Java in Spanish from scratch and without any experience in this fabulous programming language . This is the first course where we will study the Java Fundamentals, and we will take you step by step until you acquire the basics of the Java language and so you can start studying more advanced Java topics.

The content is divided into perfectly structured levels , each level supported by the previous one, with the aim of adding Java knowledge incrementally so that you can focus on mastering the issues little by little and gradually. So ensure the success of your Java training.

In other offer support of any doubt teaching materials included in this course Fundamentals of Java.

To make matters worse, we handle a new teaching methodology that we have called Speed ​​Learning. This methodology consists of concise videos that go directly to the point to study, complemented with eBooks with explanations and step-by-step images (which you can print, or search for any text you need, or use for your offline study), since as we know we cannot do text search within a video. In addition, our methodology includes perfectly structured and very didactic exercises, which will allow you to accelerate your eLearning learning. Without wasting time on videos where you have to watch the instructor codify an exercise, too much theory, little practice or anything like that. Our Speed ​​Learning methodology guarantees that in the shortest possible time you will acquire the necessary knowledge for the professional and professional world of Java.

The Java Fundamentals course includes the following topics of study:

Level. Java basics

Lesson 1 - Starting with Java Technology

The amazing world of Java programming
What is Java technology (from a practical approach)
Our first Java program from scratch
Lesson 2 - Variables and Operators in Java

Use of Variables in Java and what we use them for
Data types in Java and how they are classified
Operator Management and Classification in Java
Lesson 3 - Control sentences in Java

Use of the if-else structure and where to use it
Management of the switch structure and when to apply it
Lesson 4 - Cycle Management in Java

Use of the for cycle and its use
Use of the while cycle and how to apply it
Use of the do-while cycle and when to use it
Lesson 5 - Object Oriented Programming

Introduction to Object Oriented Programming (OOP)
Class Management in Java
Using Objects in Java
Lesson 6 - Functions in Java

Declaration of Methods or Functions in Java
Use and call of functions in Java
Lesson 7 - Data Management in Java

Using Arrangements in Java
Matrix Management in Java
Lesson 8 - Inheritance in Java

Inheritance Management in Java
Use of superclasses and subclasses in Java
Final Level Laboratory

Final Exercise where everything learned in this Level is integrated
At the end you get a certificate of having completed the Java Fundamentals course.

We wait for you from the other side.

Ing. Ubaldo Acosta

Founder of Global Mentoring

Passion for Java Technology

Who this course is for:

Anyone who wants to learn to program in Java
Basic knowledge
Basic knowledge of PC use
Basic operation of an operating system such as Windows, Mac or Linux
It is not required to know how to program, we will start from scratch !!!
The attitude and desire to start coding and learning Java once and for all from scratch !!!
What will you learn
Have the basics of the programming language with Java
You will know the basic syntax of the Java language
Will handle the concept of Variables and Operators in Java
We will study Object Oriented Programming with Java
You will learn Control Sentences and Cycles in Java
We will see the concept of Functions with Java
We will study the concept of Inheritance in Java
We will learn to use Arrangements in java
We will handle the concept of Matrices in Java
We will learn to Design Classes in Java
We will make a final application with everything learned in the course
To continue: