Java

Java 知识量:11 - 45 - 220

4.4 lambda表达式><

什么是lambda表达式- 4.4.1 -

Lambda表达式是Java 8中引入的一个新特性,其主要用于简化函数式编程。Lambda表达式在Java中主要用于创建匿名方法。这种表达式实际上是一种匿名函数,它允许我们将函数作为方法参数进行传递,或者将代码看作数据。

Lambda表达式的基本语法如下:

(parameter) -> expression

(parameter) -> { statements; }

其中:

  • parameter:这是Lambda表达式的参数列表。参数类型是可选的,也可以直接推断。例如,a -> a + 1 和 (int a) -> a + 1 是等效的。

  • ->:这个符号叫做Lambda操作符或箭头操作符,它将Lambda表达式的参数列表和体分开。

  • expression:这是Lambda表达式的主体。如果主体包含一个以上的语句,那么它需要被包含在大括号 {} 中。

例如,可以使用Lambda表达式来创建一个Runnable接口的实例,如下所示:

Runnable runnable = () -> System.out.println("Hello World");  
new Thread(runnable).start();

在这个例子中,首先创建了一个没有参数的Lambda表达式,它实现了Runnable接口的唯一方法run()。然后我们创建了一个新的线程并启动它,新线程将运行Lambda表达式定义的任务。

Lambda表达式还可以用于简化集合操作。例如,可以使用Lambda表达式来过滤一个列表:

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);  
List<Integer> evenNumbers = numbers.stream()  
                                   .filter(n -> n % 2 == 0)  
                                   .collect(Collectors.toList());

在这个例子中,使用Lambda表达式来定义过滤条件,然后使用Stream API来处理列表。

方法引用- 4.4.2 -

方法引用是一种使用现有方法的方式来代替Lambda表达式的方式。它可以看作是一种特殊的Lambda表达式,其中函数体只包含一个方法调用。方法引用的语法如下:

::methodName

其中,methodName是要调用的方法的名称。如果方法是静态的,可以使用类名来限定方法名称;如果方法是实例方法,可以使用对象来限定方法名称。

例如,下面的代码展示了如何使用方法引用来实现一个接口:

interface GreetingService {  
    void sayMessage(String message);  
}  
  
public class Main {  
    public static void main(String[] args) {  
        GreetingService greetingService = Main::sayHello;  
        greetingService.sayMessage("world");  
    }  
      
    public static void sayHello(String message) {  
        System.out.println("Hello " + message);  
    }  
}

在这个例子中,使用方法引用来实现sayMessage方法。将Main类的sayHello方法作为方法引用传递给greetingService变量。最后,调用sayMessage方法来执行方法引用。

函数式编程- 4.4.3 -

函数式编程是一种编程范式,它将计算视为数学上的函数求值,并避免改变状态和使用可变数据。在 Java 中,从 Java 8 开始,函数式编程得到了支持。下面是一个使用 Lambda 表达式进行函数式编程的示例:

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);  
  
// 使用 Lambda 表达式进行过滤  
List<Integer> evenNumbers = numbers.stream()  
                                   .filter(n -> n % 2 == 0)  
                                   .collect(Collectors.toList());  
  
// 使用 Lambda 表达式进行映射  
List<Integer> squares = numbers.stream()  
                               .map(n -> n * n)  
                               .collect(Collectors.toList());  
  
// 使用 Lambda 表达式进行排序  
List<Integer> sortedNumbers = numbers.stream()  
                                     .sorted()  
                                     .collect(Collectors.toList());  
  
// 使用 Lambda 表达式进行求和  
int sum = numbers.stream()  
                 .reduce(0, (a, b) -> a + b);

在这个示例中,首先创建了一个整数列表 numbers,然后使用 Lambda 表达式对列表进行过滤、映射、排序和求和操作。在过滤操作中,使用 Lambda 表达式 n -> n % 2 == 0 来判断一个数是否为偶数;在映射操作中,使用 Lambda 表达式 n -> n * n 来计算一个数的平方;在排序操作中,使用 Lambda 表达式默认的排序规则对列表进行排序;在求和操作中,使用 Lambda 表达式 (a, b) -> a + b 来计算列表中所有数的和。

Lambda 表达式的语法非常简洁,它由参数列表、箭头符号 -> 和 Lambda 体组成。在上面的示例中,使用了不同的 Lambda 表达式来进行不同的操作,这些表达式都非常简洁易懂。通过使用 Lambda 表达式,可以将代码看作数据,并将其作为方法的参数进行传递,这使得编写函数式代码变得更加简单和直观。

词法作用域和局部变量- 4.4.4 -

Lambda 表达式在 Java 中被用作一种简洁、易读的方式来表示函数式接口。它们可以捕获和使用在其主体中声明的变量。

  1. 词法作用域:在 Java 中,Lambda 表达式的词法作用域与其封闭的方法或构造函数的词法作用域相同。这意味着,Lambda 表达式可以访问其封闭方法或构造函数的所有可见变量。封闭方法或构造函数的成员变量对 Lambda 表达式来说是可见的,可以被直接访问。

  2. 局部变量:Lambda 表达式可以在其主体中定义局部变量。这些变量仅在 Lambda 表达式的主体中存在,不能被其封闭的方法或构造函数访问。此外,Lambda 表达式还可以在其主体中访问其封闭方法或构造函数的局部变量,但这些变量必须被声明为 final 或 effectively final。

下面是一个例子:

public class Test {  
    int x = 10; // 成员变量  
  
    public void test() {  
        int y = 20; // 局部变量  
        Runnable r = () -> {  
            int z = 30; // Lambda 表达式中的局部变量  
            System.out.println(x); // 访问成员变量 x  
            System.out.println(y); // 访问局部变量 y  
            System.out.println(z); // 访问 Lambda 表达式中的局部变量 z  
        };  
        r.run();  
    }  
}

在这个例子中,Lambda 表达式可以访问成员变量 x 和局部变量 y,因为它们都是 final 或 effectively final 的。此外,Lambda 表达式还定义了其自己的局部变量 z。