工作学习笔记(十一)Lambda 表达式
-
一、Lambda 表达式概述
Lambda 表达式是 Java 中引入的一个重要特性,它提供了一种简洁的方式来表示可传递给方法或存储在变量中的代码块。本质上,它是一种匿名函数,让开发者可以用更紧凑、更函数式的风格来编写代码,尤其在处理集合操作、事件处理以及与函数式接口配合使用等场景中非常方便。 -
二、Lambda 表达式的语法结构
Lambda 表达式的基本语法格式如下:
(parameters) -> expression 或者 (parameters) -> -
参数部分(parameters):
如果没有参数,就写一对空括号 (),例如 () -> System.out.println("无参数的 Lambda")。
若只有一个参数,参数的括号可以省略,像 param -> System.out.println(param)。
当有多个参数时,用逗号隔开,如 (param1, param2) -> param1 + param2。
箭头(->):这是 Lambda 表达式的标志性符号,用于分隔参数和表达式或语句块,表明参数如何映射到执行的代码逻辑。 -
表达式或语句块(expression 或 {statements;}):
如果表达式比较简单,能直接计算并返回一个值,就直接写表达式,例如 (a, b) -> a + b,它的返回值就是 a 与 b 相加的结果。
要是逻辑复杂,需要多条语句来实现,那就用大括号括起来形成语句块,并且如果有返回值,要明确使用 return 语句,像 (int a, int b) -> { int sum = a + b; return sum; }。 -
三、函数式接口与 Lambda 表达式
Lambda 表达式主要用于实现函数式接口。函数式接口是指只包含一个抽象方法的接口(在 Java 8 中可以使用 @FunctionalInterface 注解来显式标记一个接口是函数式接口,不过即使不标记,只要符合只含一个抽象方法的规则,依然是函数式接口)。
例如,Java 内置的 java.util.function 包中有很多函数式接口:
Runnable 接口,它只有一个抽象方法 void run(),我们可以用 Lambda 表达式来创建 Runnable 的实例,像这样:
Runnable runnable = () -> System.out.println("使用 Lambda 实现的 Runnable");
Consumer
Consumer<String> consumer = str -> System.out.println("消费的字符串是:" + str); consumer.accept("Hello");
Function<T, R> 接口,抽象方法是 R apply(T t),用于接收一个参数并返回一个结果。比如:
Function<Integer, Integer> function = num -> num * 2; int result = function.apply(5); System.out.println(result); // 输出 10
- 四、Lambda 表达式在集合操作中的应用
在 Java 中,对集合进行遍历、筛选、映射等操作时,Lambda 表达式结合一些新的方法(如 forEach、filter、map 等)能让代码更加简洁高效。
以 List 集合为例:
遍历集合:
List<String> list = Arrays.asList("apple", "banana", "cherry"); list.forEach(str -> System.out.println(str));
这里使用 forEach 方法结合 Lambda 表达式,很方便地遍历了列表中的每个元素并打印出来,相比于传统的 for 循环写法更加简洁直观。
筛选元素:
假设我们有一个 List
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6); List<Integer> evenNumbers = numbers.stream() .filter(num -> num % 2 == 0) .collect(Collectors.toList()); System.out.println(evenNumbers);
这里先通过 stream 方法将集合转换为流,然后使用 filter 方法配合 Lambda 表达式定义筛选条件(判断是否为偶数),最后用 collect 方法将符合条件的元素收集起来形成新的列表。
映射元素:
比如想把一个 List
List<String> words = Arrays.asList("hello", "world"); List<String> upperCaseWords = words.stream() .map(str -> str.toUpperCase()) .collect(Collectors.toList()); System.out.println(upperCaseWords);
map 方法结合 Lambda 表达式,按照定义的逻辑(这里是将字符串转换为大写)对集合中的每个元素进行转换,最终得到转换后的新集合。
-
五、Lambda 表达式的优势
代码简洁性:极大地减少了样板代码,让代码更加紧凑易读,尤其是在实现简单的接口方法逻辑时,避免了像匿名内部类那样冗长的写法。
函数式编程风格支持:推动 Java 往函数式编程方向发展,方便进行诸如对集合的函数式操作等,使代码逻辑更贴近数学上的函数概念,便于理解和维护。
提高开发效率:编写代码更加迅速,尤其在处理一些回调逻辑、事件处理器等场景中,能快速定义相应的行为逻辑。 -
六、注意事项
变量作用域:Lambda 表达式中访问外部变量时,外部变量必须是事实上的 final(即虽然不需要显式使用 final 关键字修饰,但在 Lambda 表达式内部不能对其重新赋值),例如:
int num = 10; Consumer<Integer> consumer = n -> { // num = 20; // 这样编译会报错,不能对外部变量重新赋值 System.out.println(num + n); }; consumer.accept(5);
异常处理:如果 Lambda 表达式中可能抛出受检异常(Checked Exception),需要在相应的函数式接口抽象方法声明中进行异常声明,或者在 Lambda 表达式内部进行合适的异常处理,不然编译会报错。