📚博客主页:代码探秘者
✨专栏:文章正在持续更新ing…
✅C语言/C++:C++(详细版) 数据结构) 十大排序算法
✅Java基础:JavaSE基础 面向对象大合集 JavaSE进阶 Java版数据结构JDK新特性
✅后端经典框架: 后端基础 SpringBoot Tlias项目(含SSM)
✅数据库:Mysql
✅常用中间件:redis入门+实战 Elasticsearch RabbitMQ
✅Linux: 部署篇
✅微服务:微服务
❤️感谢大家点赞👍🏻收藏⭐评论✍🏻,您的三连就是我持续更新的动力❤️
🙏作者水平有限,欢迎各位大佬指点,相互学习进步!
文章目录
下面 详细讲解 Java 8 的 Lambda 表达式,包括其语法、原理、使用场景以及一些注意事项。
一、入门必备
🧩 本节内容gitee仓库链接:https://gitee.com/blue-national-gold/java/tree/master/java_NewFeatures/src/com/java8/Lambda
🔹什么是 Lambda 表达式?
Lambda 表达式是一种 匿名函数,用于简洁地表示函数式接口的实例(只有一个抽象方法的接口)。本质上它是用来实现函数式接口的一种简洁写法。
🔹基本语法
(参数列表) -> { 方法体 }
✅ 简化规则
情况 | 示例 |
---|---|
无参数,无返回值 | () -> System.out.println("Hello") |
一个参数,可省略小括号 | x -> x * x |
多个参数,多行代码 | (x, y) -> { int z = x + y; return z; } |
只有一行代码且有返回值,可省略 return 和大括号 | (x, y) -> x + y |
✅ 优点
优点 | 描述 |
---|---|
简洁 | 减少冗余代码 |
易读 | 用意明确,结构清晰 |
强大 | 配合 Stream API,极大提升集合操作能力 |
高效 | 编译器优化 & JVM invokedynamic 支持 |
🔹Lambda 示例
1. 替代匿名内部类(如 Runnable)
Runnable r = () -> System.out.println("Hello from Lambda");
new Thread(r).start();
2. 用于排序(Comparator)
- 按照字符串长度排序
@Test
public void test01(){
List<String> fruits = Arrays.asList("cpp", "c", "java", "python");
fruits.sort((s1,s2)->s1.length()-s2.length()); //升序
System.out.println(fruits);
}
- 按照对象的多个字段属性排序
class Person {
String name;
int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String toString() {
return name + " (" + age + ")";
}
}
List<Person> people = Arrays.asList(
new Person("Alice", 30),
new Person("Bob", 25),
new Person("Charlie", 30),
new Person("David", 20)
);
// 按年龄升序;如果年龄相同,按名字字母排序
people.sort((p1, p2) -> {
if (p1.age != p2.age) return p1.age - p2.age;
return p1.name.compareTo(p2.name);
});
System.out.println(people);
// 输出: [David (20), Bob (25), Alice (30), Charlie (30)]
3. 与函数式接口结合使用
函数式接口就是——只定义了一个抽象方法的接口。
它的作用是:为了让你可以像传“函数”一样,传一段行为(代码)进去。
特性 | 说明 |
---|---|
只允许一个抽象方法 | 这是函数式接口的定义 |
可以有默认方法和静态方法 | 但只能有一个“真正要你实现”的抽象方法 |
用 @FunctionalInterface 标注(建议) | 编译器帮你检查是否符合要求 |
支持 Lambda 表达式创建对象 | 是 Lambda 表达式的应用基础 |
@FunctionalInterface
interface MyMath {
int operate(int a, int b);
}
public void test(MyMath m) {
int result = m.operate(20, 10);
System.out.println(result);
}
// 使用 Lambda 简化调用
test((a,b)->a+b);
test((a,b)->a-b);
test((a,b)->a*b);
test((a,b)->a/b);
🔹 常用函数式接口(Java 内置)
接口名 | 参数 | 返回值 | 用途 |
---|---|---|---|
Function<T, R> | T | R | 输入 T,返回 R |
Consumer<T> | T | void | 对 T 执行操作 |
Predicate<T> | T | boolean | 判断 T 是否满足条件 |
Supplier<T> | 无 | T | 提供 T 的实例 |
1.示例:
@Test
public void testdemo02(){
String str="AA,hello world";
//差不多Lambda表达式重写了函数式接口的apply方法
//传参返回
Function<String,Integer> f=s->s.length();
//传参不返回
Consumer<String> c=s-> System.out.println(s);
//传参,返回boolean
Predicate<String> p=s->s.startsWith("A");
//不传参,返回
Supplier<Double> s=()->Math.random();
//调用执行
System.out.println(f.apply(str));//f.apply(str) 相当与s.length()
c.accept(str);
System.out.println(p.test(str));
System.out.println(s.get());
}
演示其中一个
2.详细解释
String str="AA,hello world";
// 对应抽象方法apply
Function<String,Integer> f=s->s.length();
Integer len = f.apply(str); //f.apply(str) 相当与s.length()
System.out.println(len);
这表示:
-
Function<T, R>
是 Java 提供的一个函数式接口,表示:接受一个参数 T,返回一个结果 R。 -
这里你定义的是
Function<String, Integer>
,也就是:“接收一个
String
,返回一个Integer
(字符串长度)” -
s -> s.length()
是 Lambda 表达式,对应 Function 接口的抽象方法:
R apply(T t);
即:
@Override
public Integer apply(String s) {
return s.length();
}
3.使用方法:
int len = f.apply(str);
System.out.println(len); // 输出: 14("AA,hello world" 的长度)
4.总结:
部分 | 含义 |
---|---|
Function<String, Integer> | 接收 String ,返回 Integer |
s -> s.length() | 实现了 apply 方法,返回字符串长度 |
f.apply(str) | 执行函数,等价于 str.length() |
🔹 Lambda 的底层原理
Lambda 表达式在 Java 编译器中会被转换为 匿名类对象 或使用 invokedynamic
指令生成一个对应的函数式接口实例。
(x, y) -> x + y
相当于:
new MyMath() {
public int operate(int x, int y) {
return x + y;
}
}
🔹 使用场景
- 线程创建(Runnable)
- 排序(Comparator)
- Stream 流操作(map, filter, reduce)
- GUI 事件处理(如 Swing)
- 自定义回调
⚠️ 注意事项(重要)
-
只能用于函数式接口(一个抽象方法)
-
Lambda 不能直接访问非 final 的外部变量(但实际上支持“事实上的 final”)
-
调试困难:Lambda 出错时堆栈信息不如匿名类详细
-
避免滥用 Lambda,导致可读性降低
【其他注意】
场景 | 写法 | 是否合法 |
---|---|---|
明确指定参数类型 | (int a, int b) -> a + b | ✅ |
多行代码 | (a, b) -> { ...; return ...; } | ✅ |
省略参数类型 | (a, b) -> a * b | ✅ |
单个参数省略括号 | s -> s.toUpperCase() | ✅ |
✅明确指定参数类型时
//对应接口
@FunctionalInterface
interface MyMath {
int operate(int a, int b);
}
// 指定参数类型 int
MyMath add = (int a, int b) -> a + b;
System.out.println(add.operate(5, 3)); // 输出 8
✅代码多于一行,必须用花括号 {}
和 return
MyMath max = (a, b) -> {
System.out.println("比较两个数大小");
return a > b ? a : b;
};
System.out.println(max.operate(5, 8)); // 输出 8
如果方法体有多行,必须加花括号,而且 需要手动写 return
。
✅ 根据上下文推断参数类型(省略类型)
MyMath sub = (a, b) -> a - b;
System.out.println(sub.operate(10, 4)); // 输出 6
这里 (a, b)
没有写类型,因为编译器已经知道 MyMath.operate(int, int)
要的是两个 int
。
✅参数只有一个,可以省略小括号 ()
Consumer<String> printer = s -> System.out.println(s.toUpperCase());
printer.accept("hello"); // 输出:HELLO
- 如果参数是两个或没有,就不能省略括号。
(a, b)没有写类型,因为编译器已经知道
MyMath.operate(int, int)要的是两个
int`。
✅参数只有一个,可以省略小括号 ()
Consumer<String> printer = s -> System.out.println(s.toUpperCase());
printer.accept("hello"); // 输出:HELLO
- 如果参数是两个或没有,就不能省略括号。