Java Lambda表达式入门教程
1. 什么是Lambda表达式?
Java 8 引入的 Lambda 表达式本质上是一个可以传递的匿名函数。它允许我们将函数作为参数传递给方法,或者将代码视为数据。Lambda 表达式极大地简化了函数式编程风格的代码编写,尤其是在集合操作、事件处理和并发编程等场景下,可以替代过去冗长的匿名内部类。
2. 函数式接口
在深入 Lambda 之前,必须先理解函数式接口。函数式接口是只包含一个抽象方法的接口(可以有多个默认方法或静态方法)。Lambda 表达式只能用于实现函数式接口。例如,我们定义两个接口:
// 无参数、无返回值的函数式接口interfaceDemo1{voidshow();}// 有参数、有返回值的函数式接口interfaceDemo2{intadd(inta,intb);}两个接口都只声明了一个抽象方法,因此都是合法的函数式接口。Lambda 表达式就是这些抽象方法的实现。
3. Lambda 表达式语法
基本语法格式如下:
- (parameters) -> expression
当方法体只有一条语句且直接作为返回值时,可以省略大括号和return。 - (parameters) -> { statements; }
当方法体包含多条语句,或需要显式书写return、抛出异常等时,必须使用大括号。
参数类型可以省略(由编译器根据上下文推断),如果只有一个参数且无类型,还可以省略小括号。但为了清晰,通常保留括号。
4. 实战:从匿名内部类到 Lambda
下面我们从一个完整的示例出发,逐步展示如何用 Lambda 表达式替代匿名内部类,并理解其运行过程。
4.1 传统匿名内部类写法(对比)
publicclassTraditionalDemo{publicstaticvoidrun1(Demo1d){d.show();}publicstaticvoidrun2(Demo2d){System.out.println(d.add(1,2));}publicstaticvoidmain(String[]args){// 匿名内部类实现 Demo1run1(newDemo1(){@Overridepublicvoidshow(){System.out.println("Hello Java");}});// 匿名内部类实现 Demo2run2(newDemo2(){@Overridepublicintadd(inta,intb){returna+b;}});}}4.2 Lambda 表达式重构
使用 Lambda 表达式后,代码大幅精简:
// 函数式接口定义interfaceDemo1{voidshow();}interfaceDemo2{intadd(inta,intb);}publicclassLambdaDemo{publicstaticvoidrun1(Demo1d){d.show();// 调用对象的方法}publicstaticvoidrun2(Demo2d){System.out.println(d.add(1,2));}publicstaticvoidmain(String[]ages){// 1. 无参无返回值的 Lambdarun1(()->System.out.println("Hello Java"));// 2. 有参数有返回值的 Lambda(单条语句,省略 return 和大括号)run2((a,b)->a+b);// 3. 多行语句的 Lambda,必须使用大括号run1(()->{System.out.println("Hello");System.out.println("World");});}}运行结果:
Hello Java 3 Hello World4.3 代码解读
() -> System.out.println("Hello Java")对应Demo1接口的void show()方法。小括号为空表示无参;箭头后面是只有一条语句的方法体。(a, b) -> a + b对应Demo2接口的int add(int a, int b)。参数类型被自动推断为int;表达式a + b的值自动作为返回值,无需return关键字。- 当方法体超过一条语句时,必须用大括号包裹,每条语句末尾加分号,这与普通方法体写法一致。Lambda 在这里只是让代码更紧凑,但并未改变 Java 基本的代码块规则。
5. 常用函数式接口与进阶
Java 8 在java.util.function包中提供了一系列标准函数式接口,避免大家重复造轮子。常用四个:
| 接口 | 抽象方法 | 说明 |
|---|---|---|
Predicate<T> | boolean test(T t) | 断言型,判断输入是否满足某条件 |
Consumer<T> | void accept(T t) | 消费型,对输入执行某种操作,不返回结果 |
Function<T,R> | R apply(T t) | 函数型,接收 T,返回 R |
Supplier<T> | T get() | 供给型,无参但返回一个结果 |
示例:
importjava.util.function.*;publicclassFunctionalInterfaceDemo{publicstaticvoidmain(String[]args){// Predicate: 判断是否大于5Predicate<Integer>isGreaterThan5=x->x>5;System.out.println(isGreaterThan5.test(10));// true// Consumer: 打印字符串Consumer<String>printer=s->System.out.println("输出:"+s);printer.accept("Hello Lambda");// Function: 求字符串长度Function<String,Integer>lengthFunc=str->str.length();System.out.println(lengthFunc.apply("Hello"));// Supplier: 生成随机数Supplier<Double>randomSupplier=()->Math.random();System.out.println(randomSupplier.get());}}方法引用简介
当 Lambda 体只是调用一个已经存在的方法时,可以进一步简化为方法引用,格式为类名::方法名或对象::方法名。
// Lambda 写法Consumer<String>printer1=s->System.out.println(s);// 方法引用Consumer<String>printer2=System.out::println;方法引用使代码更加简洁易读,是 Lambda 的一种重要补充形式。
Lambda 表达式以函数式接口为基石,通过简洁的语法和丰富的标准接口,打开了 Java 函数式编程的大门。
6. 总结
- Lambda 表达式是 Java 8 中实现函数式接口的精简方式,本质是匿名函数。
- 函数式接口有且只有一个抽象方法,是 Lambda 的载体。
- 语法由参数列表、箭头、方法体组成,单条语句可省大括号和
return。 - Java 标准库提供了
Predicate、Consumer、Function、Supplier等丰富的函数式接口,极大方便了流式操作与函数式编程。 - 方法引用是 Lambda 的语法糖,当 Lambda 仅仅是调用一个已有方法时推荐使用。
掌握 Lambda 表达式将帮助你写出更简洁、优雅的 Java 代码,并为学习 Stream API、并行流等高级特性打下坚实基础。
