# Lambda 表达式

> 原文： [https://howtodoinjava.com/java8/lambda-expressions/](https://howtodoinjava.com/java8/lambda-expressions/)

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

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

![lambda](img/7c3f5e72f935bdced64cee2445f6ad7a.png)

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

```java
 Table of Contents
1\. What is a lambda expression in Java?
2\. Java 8 functional interface
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 表达式语法如下所示：

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

```

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

语法：

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

```java
either

(parameters) -> expression 			//1

or

(parameters) -> { statements; } 	//2

or 

() -> expression 					//3

```

#### 1.2 Lambda 示例

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

```java
(int a, int b) -> 	a * b          		// takes two integers and returns their multiplication

(a, b) 			-> 	a - b               // takes two numbers and returns their difference

() -> 99                                // takes no values and returns 99

(String a) -> System.out.println(a)     // takes a string, prints its value to the console, and returns nothing 

a -> 2 * a                               // takes a number and returns the result of doubling it

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`接口的新定义是这样的：

```java
@FunctionalInterface
public interface Runnable {
	public abstract void run();
}

```

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

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

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

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

```java
new Thread(new Runnable() {
	@Override
	public void run() {
		System.out.println("howtodoinjava");
	}
}).start();

```

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

```java
new Thread(
			() ->   { 
						System.out.println("My Runnable"); 
					}
		 ).start();

```

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

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

## 3\. Java 8 lambda 表达式示例

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

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

```java
List<String> pointList = new ArrayList();
pointList.add("1");
pointList.add("2");

pointList.forEach(p ->  {
							System.out.println(p);
							//Do more work
						}
				 );

```

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

```java
new Thread(
    () -> System.out.println("My Runnable"); 
).start();

```

**3）按员工名称**对其排序

```java
public class LambdaIntroduction {

  public static void main (String[] ar){
          Employee[] employees  = {
              new Employee("David"),
              new Employee("Naveen"),
              new Employee("Alex"),
              new Employee("Richard")};

          System.out.println("Before Sorting Names: "+Arrays.toString(employees));
          Arrays.sort(employees, Employee::nameCompare);
          System.out.println("After Sorting Names "+Arrays.toString(employees));
      }
}

class Employee {
  String name;

  Employee(String name) {
    this.name = name;
  }

  public static int nameCompare(Employee a1, Employee a2) {
    return a1.name.compareTo(a2.name);
  }

  public String toString() {
    return name;
  }
}

Output:

Before Sorting Names: [David, Naveen, Alex, Richard]
After Sorting Names [Alex, David, Naveen, Richard]

```

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

```java
JButton button =  new JButton("Submit");
button.addActionListener((e) -> {
    System.out.println("Click event triggered !!");
});           

```

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

学习愉快！