Introduction to Java 8 Lambda Expressions

Posted PrimerPlus

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Introduction to Java 8 Lambda Expressions相关的知识,希望对你有一定的参考价值。

Lambda expressions were introduced in Java 8 and they became the talk of the town as soon as they arrived.

Java has evolved a lot with time. It has incorporated new ideas and programming paradigms as and when necessary. That is the main reasons why It is still the most used language worldwide.

Functional programming was on the rise when Lambda expressions were introduced in Java 8.

Java embraced functional programming by introducing several new features in Java 8 like Lambda Expressions, Stream API, Optional etc.

In this article, you’ll learn what lambda expression is, how it works under the hood, and how to use it effectively in your programs.

The need for lambda expressions

Java is a pure object oriented programming language. Everything in Java is an Object with the exception of primitive types.

Java是一种纯粹的面向对象的编程语言。Java中所有的内容都是对象,原始类型除外。

You can’t define top level functions (functions that don’t belong to a class) in Java. You can’t pass a function as an argument, or return a function from another function.

您无法在Java中定义顶级函数(不属于类的函数)。您不能将函数作为参数传递,也不能从另一个函数返回函数。

So, what’s the alternative?

Before lambda expressions were introduced, Developers used to use Anonymous class syntax for passing functionality to other methods or constructors.

在引入lambda表达式之前,开发人员曾经使用匿名类语法将功能传递给其它方法或构造函数。

Let’s see an example of anonymous class syntax. Consider the following Employee class -

class Employee {
    private String name;
    private int age;

    // Constructor, Getters, Setters (Omitted for brevity)
}

Now, To sort a list of employees, we usually pass a custom comparator to the List.sort() method as described in the following example -

现在,为了对员工列表进行排序,我们通常将自定义比较器传递给List.sort()方法,如以下示例中所述-

List<Employee> employees = Arrays.asList(new Employee("Foo", 21),
        new Employee("Bar", 25));

// Sort employees based on their age by passing an anonymous comparator.
employees.sort(new Comparator<Employee>() {
    @Override
    public int compare(Employee e1, Employee e2) {
        return e1.getAge() - e2.getAge();
    }
});

In the above example, we wanted to pass a single compare() functionality to the sort() method for comparing two Employees.

在上面的示例中,我们希望将单个compare()功能传递给sort()方法,以比较两个Employees。

For doing this, we had to create an anonymous comparator object with the implementation of the compare() function, and pass it in the sort() method.

为此,我们必须使用compare()函数的实现创建一个匿名比较器对象,并将其传递给sort()方法。

Consider another example of an anonymous Runnable -

// Create a thread by passing an Anonymous Runnable.
Thread myThread = new Thread(new Runnable() {
    @Override
    public void run() {
        // Code to be executed inside the thread;
    }
});

In this example, we wanted to create a thread and pass a function that needs to be executed by the thread.

在此示例中,我们想要创建一个线程并传递一个需要该线程执行的函数。

For doing this, we had to create an anonymous Runnable object with the implementation of the run() method and pass the object to the Thread() constructor.

为此,我们必须使用run()方法的实现创建一个匿名Runnable对象,并将该对象传递给Thread()构造函数。

You’re getting the point right? Since you can’t pass functions directly as method arguments, You need to write all that boilerplate code all the time.

由于不能直接将函数作为方法参数传递,因此您需要一直编写所有样板代码。

I agree that anonymous class syntax is more compact than defining a named class, instantiating it and then passing the instance as an argument. It is still too much for classes with only one method.

匿名类语法比定义命名类,实例化它然后将实例作为参数传递要紧凑得多。

Can we do better? Is there a simpler way of passing a single functionality to other methods?

Well, Enter Lambda Expressions!

Introduction to Lambda Expression

Lambda expression allows you to pass functionality to other methods in a less verbose and more readable way.

Lambda表达式使您可以以较少冗长和更易读的方式将功能传递给其它方法。

Here is how you would write the earlier employee comparator example using lambda expression -

employees.sort((Employee e1, Employee e2) -> {
    return e1.getAge() - e2.getAge();
});

If the method body consists of a single line, then you can omit the curly braces and the return keyword as well -

employees.sort((Employee e1, Employee e2) -> e1.getAge() - e2.getAge());

Moreover, Since Java is aware about the types of arguments from the surrounding context, you can omit the type declarations as well -

employees.sort((e1, e2) -> e1.getAge() - e2.getAge());

Whoa! Compare that with the earlier implementation without lambda expression. This is so concise, readable, and to the point.

What about the Runnable example? Well, Here is how you would write that using lambda expression -

Thread myThread = new Thread(() -> {
    // Code to be executed inside the thread    
});

Syntax and Examples of Lambda Expressions

Lambda expressions in Java has the following syntax -

(type arg1, type arg2, type arg3, ...) -> (body)

Note that, the type declaration can be omitted from the arguments because the compiler can infer the types of arguments from the surrounding context -

请注意,可以从参数中省略类型声明,因为编译器可以从周围的上下文中推断出参数的类型

(arg1, arg2, arg3, ...) -> (body)

Here are some examples of lambda expressions -

// Accepts no arguments and returns void
() -> System.out.println("Hello, World!");
// Accepts two int arguments and returns int
(int a, int b) -> a+b;
// Accepts an Integer and returns boolean
(Integer n) -> {
    // (Checks if the number is prime or not)
    if (n <= 1)  return false;

    for (int i=2; i <= Math.sqrt(n); i++)
        if (n%i == 0)
            return false;

    return true;
};

Lambda Expressions Under the Hood

Introducing Functional Interfaces

Contrary to other functional programming languages, lambda expressions in Java do not correspond to functions.

与其它函数式编程语言相反,Java中的lambda表达式与函数式不对应。

Lambda expressions in Java are instances of Functional Interfaces. A functional interface is an interface that contains exactly one abstract method.

Java中的Lambda表达式是函数式接口的实例。函数式接口是仅包含一个抽象方法的接口

For example, Runnable is a functional interface because it contains exactly one abstract method run(). Similarly, Comparator is a functional interface with a single abstract method compare().

例如,Runnable是一个函数式接口,因为它只包含一个抽象方法run()。同样,Comparator是具有单个抽象方法compare()的函数式接口。

Did you know? You can also define non-abstract methods inside an interface with the help of Java 8’s default keyword. Since default methods are not abstract, a functional interface can have multiple default methods.

可以借助Java 8的默认关键字在接口内定义非抽象方法。由于默认方法不是抽象的,因此函数式接口可以具有多个默认方法。

Although, any interface with a single abstract method can be used as a lambda expression. To make sure that the interface meets the requirements of a functional interface, you should add a @FunctionalInterface annotation like so -

虽然,任何具有单个抽象方法的接口都可以用作lambda表达式。为确保该接口满足函数式接口的要求,应添加一个@FunctionalInterface注解

@FunctionalInterface
interface MyFunctionalInterface {
    void test();
}

The compiler throws an error if an interface annotated with @FunctionalInterface annotation does not meet the requirements of a functional interface.

如果使用@FunctionalInterface注解的接口不满足函数式接口的要求,则编译器将引发错误。

Java 8 comes with a bunch of built-in functional interfaces. All of them are defined in the java.util.function package. Check out the Official Java Doc for more information.

Java 8附带了一堆内置的函数式接口。所有的这些都在java.util.function包中定义。

Understanding the relation between lambda expressions and functional interfaces

了解Lambda表达式与函数式接口之间的关系

Every lambda expression in Java is internally mapped to a functional interface. The functional interface to which a lambda expression will be mapped is determined by the compiler from its surrounding context at compile time.

Java中的每个lambda表达式都在内部映射到函数式接口。Lambda表达式将映射到的函数式接口由编译器在编译时根据其周围上下文确定

Consider the following lambda expression for example -

// A lambda expression that accepts no arguments and returns void
() -> System.out.println("Hello, World!")

It can be mapped to any functional interface whose abstract method takes no arguments and returns void.

可以将其映射到其抽象方法不带任何参数并返回void的任何函数式接口

For example, It can be mapped to a Runnable interface because a Runnable contains a single abstract method run() that takes no arguments and returns void -

例如,可以将其映射到Runnable接口,因为Runnable包含单个抽象方法run(),该方法不带任何参数并返回void-

Runnable myRunnable = () -> System.out.println("Hello, World!");

Since our lambda expression maps to a Runnable, we can use it in any context where an instance of Runnable is required. For example, we can use it in Thread(Runnable target) constructor as we did in our earlier example -

由于lambda表达式映射到Runnable,因此我们可以在需要Runnable实例的任何上下文中使用它。例如,我们可以像在前面的示例中那样在Thread(Runnable target)构造函数中使用它-

Thread myThread = new Thread(() -> System.out.println("Hello, World!"));

Let’s consider another lambda expression -

// A lambda expression that accepts a single argument and returns void
(value) -> System.out.println(value)

This lambda expression can be mapped to any functional interface whose abstract method takes a single argument and returns void.

There are many such built-in functional interfaces in Java to which the above lambda expression can be mapped -

Java中有许多这样的内置功能接口,上述lambda表达式可以映射到这些接口:

IntConsumer myIntConsumer = (value) -> System.out.println(value);

LongConsumer myLongConsumer = (value) -> System.out.println(value);

DoubleConsumer myDoubleConsumer = (value) -> System.out.println(value);

Consumer<String> myStringConsumer = (value) -> System.out.println(value);

All of the above functional interfaces are defined in java.util.function package.

Also note that - the type of the argument value is inferred from the context at compile time. It’s type will be int when it’s used with IntConsumer, long when it’s used with LongConsumer and so on.

还要注意-参数值的类型是在编译时从上下文推断出来的。与IntConsumer一起使用时,该类型将为int;与LongConsumer一起使用时,该类型将为long

Since, this lambda expression can be mapped to all of the above functional interfaces, we can use it in any context where an instance of any of the above functional interfaces is required.

由于该lambda表达式可以映射到所有上述函数式接口,因此我们可以在需要上述任何函数式接口的实例的任何上下文中使用它

Conclusion

Lambda expression was one of the key features of Java 8. It was the first step towards functional programming in Java.

In this article, I’ve tried to explain the need for lambda expressions, how to use it in your programs and how it fits in the Java’s type System.

I hope this article was helpful to you. Thank you for reading folks. See you in the next post!

以上是关于Introduction to Java 8 Lambda Expressions的主要内容,如果未能解决你的问题,请参考以下文章

[Introduction to programming in Java 笔记] 1.3.7 Converting to binary 十进制到二进制的转换

[Introduction to programming in Java 笔记] 1.3.9 Factoring integers 素因子分解

2013 UBC Machine Learning NO.7 Introduction to Gaussian Processes NO.8 Gaussian Processes

Brief introduction to Java String Split 简单介绍下Java String Split

面向对象编程导论 An Introduction to Object-Oriented Programming

Oracle LiveLabs实验:Introduction to Oracle Spatial Studio