💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
# Lambda 表达式简介 > 原文: [https://javabeginnerstutorial.com/core-java-tutorial/introduction-lambda-expressions/](https://javabeginnerstutorial.com/core-java-tutorial/introduction-lambda-expressions/) 在本文中,我将向您简要介绍 Java 8 的一项新功能:lambda 表达式。 我将向您展示什么是 lambda 表达式以及如何利用这一新功能。 ## 什么是 lambda 表达式? Lambda 表达式类似于其他编程语言中的闭包-或 Java 本身中的匿名函数或内部类。 Lambda 表达式希望利用匿名类的用法。 您可能还记得将操作监听器注册到图形用户界面中的按钮的方式: ```java JButton clickMeButton = new JButton("Click me!"); clickMeButton.addActionListener(new ActionListener(){ @Override public void actionPerformed(ActionEvent event){ System.out.println("You clicked me!"); } }); ``` 是的,上面的代码向您展示了一个匿名内部类,该类仅用于实现`ActionListener`接口的唯一方法`actionPerformed(ActionEvent)`。 而且这很笨拙—即使现代的 IDE 可以帮助您完成代码填充以填充方法的主体。 但是,使用 lambda 表达式,您可以像下面这样简单地实现此方法: ```java JButton clickMeButton = new JButton("Click me!"); clickMeButton.addActionListener(event -> System.out.println("You clicked me!")); ``` 这样好多了,不是吗? 现在该深入了解如何构建自己的 lambda 表达式了。 Lambda 表达式具有以下语法: ```java parameters -> expression body ``` lambda 表达式的关键是`->`箭头符号。 让我们看一个基本的示例: ```java (int x) -> { return x * x; }; ``` 还有其他一些特征可以简化 lambda 表达式的使用: * 如果仅需要一个参数,则括号在参数周围是可选的 * 参数的类型声明是可选的 * `return`语句是可选的 * 表达式主体周围的花括号是可选的—如果表达式主体包含单个语句 因为我们的简单表达式符合上述所有四个要点,所以我们可以像这样覆盖 lambda 表达式: ```java x -> x * x; ``` 这使事情更具可读性。 ## 函数式接口 Lambda 表达式可用于实现所谓的**函数式接口**的方法。 较新的接口可以带有注解`@FunctionalInterface`,以指示此接口是函数式接口-但是,每个接口都可以视为仅具有**一个抽象方法**的函数式接口。因此,即使接口没有被非正式地标记为`FunctionalInterface`,也可以使用 lambda 表达式替换/实现`ActionListener`的`addActionListener`。 默认方法不具有抽象性,因为它们具有实现。 如果接口在不提供实现的情况下覆盖了`java.lang.Object`的方法,则该实现也不会被视为抽象,因为该实现将继承`java.lang.Object`类的实现。 让我们来看一个示例: ```java /** * @author GHajba * */ public interface ExampleFunctionalInterface { /** * @return a name */ String getName(); /** * prints a greeting */ default void printGreeting() { System.out.println("Hello " + getName() + "!"); } /** * * @return the string representation of this object */ @Override String toString(); } ``` 即使我们不添加注解,上面的接口也是一个函数式接口。 现在,我们创建一个 lambda 并使用它。 请记住,我们的 lambda 必须仅实现`getName()`函数,该函数不需要任何参数并返回`String`: ```java final ExampleFunctionalInterface example = () -> "GHajba"; // implements the getName() function example.printGreeting(); System.out.println(example); // this calls example.toString() implicitly ``` 如果运行示例,我们将得到与以下结果类似的结果: ```java Hello GHajba! ChangeCalculator$$Lambda$1/[[email protected]](/cdn-cgi/l/email-protection) ``` 如您所见,默认方法可以与实现的 lambda 一起正常工作,并且可以从`java.lang.Object`调用`toString`,因为不存在 lambda 表达式中的直接实现。 ## 更多示例 了解了 lambda 表达式后,我们来看一些示例,在这些示例中我们可以使用它们来改进现有或新代码。 因为 lambda 表达式是匿名函数或内部类,所以我们可以用它们替换对现有匿名函数的调用。 就像 GUI 应用的动作监听器或`Runnable`接口的本地实现一样。 ```java final Runnable runnable = new Runnable() { @Override public void run() { System.out.println("Hello lambdas?"); } }; runnable.run(); ``` 上面的示例使用匿名类实现`Runnable`接口。 现在来看看这个简单的“你好 lambdas”吗? 输出这是要做的一些工作。 ```java final Runnable runnable_lambdas = () -> System.out.println("Hello lambdas!"); runnable_lambdas.run(); ``` 上面的代码示例使用 lambda 表达式,并且做完全相同的事情:它输出字符串“`Hello lambdas!`”。 到控制台-但是无需创建匿名类来实现`Runnable`接口。 自然,此代码仅适用于函数式接口(只有一种方法的接口)。 如您所见,也可以创建无参数的 lambda。 为此,您需要提供空括号作为参数,以表明没有任何内容。 除此之外,lambda 表达式也是闭包。 这意味着它们是可以保存在变量中并在以后重用的函数。 如果我们看一下上一节中的示例,我们可以将其保存到一个名为`square`的变量中,并在以后重用: ```java IntUnaryOperator square = x -> x * x; ``` 要使用它,我们可以直接调用它,也可以在某些流表达式中使用它,例如`map`: ```java System.out.println(square.applyAsInt(128)); System.out.println("------"); IntStream.rangeClosed(1, 10).map(square).forEach(System.out::println); ``` 上面的代码片段的结果是这样的: ```java 16384 ------ 1 4 9 16 25 36 49 64 81 100 ``` ## 柯里化 柯里化是函数部分应用的名称。 这就是说,您有一个函数,该函数需要多个参数,但是大多数参数已经为人所知,并且将保持不变-只有一个会发生变化。 而且,除了在调用函数时提供每个参数之外,还可以部分咖喱函数并设置一些默认参数。 让我们看一下以下示例: ```java public static Function<Integer, Function<Integer, Integer>> multiply() { return x -> y -> x * y; } ``` 这段代码创建了一个简单的函数,将两个`Integer`类型的变量相乘。 因为返回的函数需要两个参数(x 和 y),所以我们可以创建这些函数的当前版本并在以后使用它们: ```java final Function<Integer, Integer> two_times = multiply().apply(2); final Function<Integer, Integer> three_times = multiply().apply(3); ``` 现在,我们对每个函数都应用了一个(变量)变量。 如果调用这些函数(应用第二个变量),我们可以看到结果表示已经应用的值: ```java System.out.println(two_times.apply(3)); // prints 6 System.out.println(three_times.apply(3)); // prints 9 ``` 每次自然地调用`apply()`有点麻烦,但是 Java 目前无法使其变得更好。 如果可以编写以下代码,则将是更好的语法: ```java final Function<Integer, Integer> two_times = multiply()(2) System.out.println(two_times(3)); ``` 这目前尚不起作用,但是添加到 Java 语言中将是一个不错的语法糖。 ## 总结 如果您要实现函数式接口而无需创建和实例化实现该接口的类,那么 Lambda 表达式功能强大-主要是因为您只需要一次(例如,用作按钮的`ActionListener`)。 我们研究了珂里化/函数部分应用,并讨论了一些功能将使其更易于在 Java 中使用,并希望在将来的版本中我们可以使用它。