原文: https://howtodoinjava.com/java8/lambda-expressions/

java lambda 表达式是 Java 8 附带的一个非常令人兴奋的新特性。 对于我们许多使用 scala 之类的高级语言工作的人来说,它们并不陌生。

实际上,如果您回顾历史并尝试找出过去 20 年中 Java 语言的任何改进,您将无法回忆起许多令人兴奋的事情。 在过去的十年中,java 中只有很少的并发类,泛型,如果您也同意,那么注释也是如此。 Lambda 表情打破了这种干旱,感觉就像是一件令人愉快的礼物。

Lambda 表达式 - 图1

在本文中,我将分三部分介绍 lambda 表达式及其概念。 以下是继续进行的计划。

  1. Table of Contents
  2. 1\. What is a lambda expression in Java?
  3. 2\. Java 8 functional interface
  4. 3\. Lambda expression examples

让我们坚持计划并逐步进行。

1. Java 中的 lambda 表达式是什么?

在编程中, Lambda 表达式(或函数)只是一个匿名函数,即不带名称且不受标识符约束的函数。

换句话说,lambda 表达式是无名称的函数,以常量值形式给出,并精确地写在需要的地方,通常作为其他函数的参数

Lambda 表达式的最重要特征是它们在其出现的上下文中执行。 因此,类似的 lambda 表达式可以在其他一些上下文中以不同的方式执行(即逻辑是相同的,但基于传递给函数的不同参数,结果将有所不同)。

上面的定义充满了关键字,只有当您已经深入了解什么是 lambda 表达式时才能理解。 因此,一旦您对下一部分中的 lambda 表达式有了更好的了解,我建议您重新阅读以上段落。

因此,很明显 lambda 是某种没有名称和标识符的函数。 好吧,有什么大不了的? 为什么每个人都这么兴奋?

答案在于,与面向对象编程(OOP)相比,函数式编程所带来的好处。 大多数 OOP 语言围绕对象和实例发展,并且仅将它们作为头等公民对待。 另一个重要的实体,即职能倒退。 在 Java 中尤其如此,在 Java 中,函数不能存在于对象外部。 函数本身在 Java 中没有任何意义,直到它与某个对象或实例相关为止。

但是在函数式编程中,您可以定义函数,为它们提供引用变量并将其作为方法参数传递等等。 JavaScript 是一个很好的例子,您可以在其中传递回调方法,例如到 Ajax 调用。 这是非常有用的特性,并且从一开始就在 Java 中缺少。 现在使用 Java 8,我们也可以使用这些 lambda 表达式。

1.1 Lambda 语法

典型的 lambda 表达式语法如下所示:

  1. (x, y) -> x + y //This function takes two parameters
  2. //and return their sum.

现在基于xy的类型,可以在多个地方使用方法。 参数可以匹配intInteger或简单地也可以匹配String。 根据上下文,它将添加两个整数或连接两个字符串。

语法:

lambda 表达式的其他可能语法为:

  1. either
  2. (parameters) -> expression //1
  3. or
  4. (parameters) -> { statements; } //2
  5. or
  6. () -> expression //3

1.2 Lambda 示例

我们还来看一些 lambda 表达式的示例:

  1. (int a, int b) -> a * b // takes two integers and returns their multiplication
  2. (a, b) -> a - b // takes two numbers and returns their difference
  3. () -> 99 // takes no values and returns 99
  4. (String a) -> System.out.println(a) // takes a string, prints its value to the console, and returns nothing
  5. a -> 2 * a // takes a number and returns the result of doubling it
  6. c -> { //some complex statements } // takes a collection and do some procesing

1.3 Lambda 表达式的特性

让我们确定 lambda 表达式的一些特性:

  1. Lambda 表达式可以具有零个,一个或多个参数。
  2. 参数的类型可以显式声明,也可以从上下文中推断出来。
  3. 多个参数用强制括号括起来,并用逗号分隔。 空括号用于表示空参数集。
  4. 当有单个参数时,如果推断出其类型,则不强制使用括号。 例如a -> a * a
  5. Lambda 表达式的主体可以包含零个,一个或多个语句。
  6. 如果 lambda 表达式的主体具有单个语句,则不必使用大括号,并且匿名函数的返回类型与主体表达式的返回类型相同。 如果正文中的语句多于一个,则这些语句必须用大括号括起来。

因此,我们简要了解了什么是 lambda 表达式。 如果您感到迷茫且无法联系,请耐心等待,如何在 Java 编程语言中使用它。 我们将在接下来的 30 分钟内解决所有问题。 让我们开始吧。

在深入研究 lambda 表达式和 Java 编程之间的关系之前,您还必须了解函数式接口。 这太重要了。

2. Java 8 函数式接口

单一抽象方法接口(SAM 接口)不是一个新概念。 这意味着仅使用一种方法进行接口。 在 Java 中,我们已经有许多此类 SAM 接口的示例。 从 Java 8 开始,它们也将也称为函数式接口。 Java 8 通过使用新的注释(即@FunctionalInterface)标记这些接口来实现单一职责规则。

例如,Runnable接口的新定义是这样的:

  1. @FunctionalInterface
  2. public interface Runnable {
  3. public abstract void run();
  4. }

如果尝试在任何函数式接口中添加新方法,则编译器将不允许您执行此操作,并且会引发编译时错误。

到目前为止,一切都很好。 但是,它们与 Lambda 表达式有何关系? 让我们找出答案。

我们知道 Lambda 表达式是不带名称的匿名函数,它们(大多数)作为参数传递给其他函数。 好吧,在 Java 方法中,参数总是具有类型,并且在确定方法重载甚至是简单方法调用的情况下,都会寻找此类型信息以确定需要调用哪个方法。 因此,基本上每个 lambda 表达式也必须都可以转换为某种类型才能被接受为方法参数。 好吧,用于转换 lambda 表达式的类型始终是函数式接口类型

让我们通过一个例子来理解它。 如果我们必须编写一个在控制台上打印"howtodoinjava"的线程,那么最简单的代码将是:

  1. new Thread(new Runnable() {
  2. @Override
  3. public void run() {
  4. System.out.println("howtodoinjava");
  5. }
  6. }).start();

如果我们使用 lambda 表达式执行此任务,则代码将为:

  1. new Thread(
  2. () -> {
  3. System.out.println("My Runnable");
  4. }
  5. ).start();

我们还看到Runnable是具有单个方法run()的函数式接口。 因此,当您将 lambda 表达式传递给Thread类的构造器时,编译器将尝试将该表达式转换为等效的Runnable代码,如第一个代码示例所示。 如果编译器成功,则一切运行良好,如果编译器无法将表达式转换为等效的实现代码,它将抱怨。 在此,在上面的示例中,lambda 表达式被转换为Runnable类型。

简单来说,lambda 表达式是函数式接口的实例。 但是,lambda 表达式本身并不包含有关它正在实现哪个函数接口的信息。 该信息是从使用它的上下文中推导出来的。

3. Java 8 lambda 表达式示例

我列出了一些代码示例,您可以阅读并分析如何在日常编程中使用 lambda 表达式。

1)遍历一个列表并执行一些操作

  1. List<String> pointList = new ArrayList();
  2. pointList.add("1");
  3. pointList.add("2");
  4. pointList.forEach(p -> {
  5. System.out.println(p);
  6. //Do more work
  7. }
  8. );

2)创建一个新的可运行对象,并将其传递给线程

  1. new Thread(
  2. () -> System.out.println("My Runnable");
  3. ).start();

3)按员工名称对其排序

  1. public class LambdaIntroduction {
  2. public static void main (String[] ar){
  3. Employee[] employees = {
  4. new Employee("David"),
  5. new Employee("Naveen"),
  6. new Employee("Alex"),
  7. new Employee("Richard")};
  8. System.out.println("Before Sorting Names: "+Arrays.toString(employees));
  9. Arrays.sort(employees, Employee::nameCompare);
  10. System.out.println("After Sorting Names "+Arrays.toString(employees));
  11. }
  12. }
  13. class Employee {
  14. String name;
  15. Employee(String name) {
  16. this.name = name;
  17. }
  18. public static int nameCompare(Employee a1, Employee a2) {
  19. return a1.name.compareTo(a2.name);
  20. }
  21. public String toString() {
  22. return name;
  23. }
  24. }
  25. Output:
  26. Before Sorting Names: [David, Naveen, Alex, Richard]
  27. After Sorting Names [Alex, David, Naveen, Richard]

4)将事件监听器添加到 GUI 组件

  1. JButton button = new JButton("Submit");
  2. button.addActionListener((e) -> {
  3. System.out.println("Click event triggered !!");
  4. });

上面是 Java 8 中 lambda 表达式的非常基本的示例。我将不时提出一些更有用的示例和代码示例。

学习愉快!