😫 痛点引入 :匿名内部类写一堆
new Runnable() { @Override ... },三行代码只干一件事?Lambda 表达式一句话搞定!配合四大函数式接口,Java 代码像写诗一样优雅!📘
今天从 Lambda 语法到 Consumer/Supplier/Function/Predicate,一篇让你的代码「瘦身」80%!
一、Lambda 表达式是什么?🤔
1.1 一句话理解
Lambda = 匿名内部类的简化版,把「new 接口(){ 重写方法 }」变成「()-> 方法体」
1.2 ⚠️ 使用前提:函数式接口
✅ 能用 Lambda 的接口:只有一个抽象方法(函数式接口)
❌ 不能用 Lambda 的类/接口:普通类、多个抽象方法的接口
java
// 匿名内部类(之前)
Runnable r1 = new Runnable() {
@Override
public void run() {
System.out.println("run方法体");
}
};
// Lambda 表达式(之后)✨ 三行变一行!
Runnable r2 = () -> System.out.println("run方法体");
二、Lambda 语法格式 🏗️
2.1 基本结构
(参数列表) -> { 方法体 }
↑ ↑ ↑
参数们 箭头 要执行的代码
2.2 四种语法格式速查表
| 格式 | 写法 | 省略规则 | 适用场景 |
|---|---|---|---|
| 无参无返回值 | ()->{ body } |
body 只有一句可省略 {} |
Runnable |
| 有参无返回值 | (x)->{ body } |
一个参数可省略 () |
Consumer |
| 多参无返回值 | (x,y)->{ body } |
body 只有一句可省略 {} |
BiConsumer |
| 有参有返回值 ⭐ | (x,y)->{ return x; } |
只有 return 可省略 {} 和 return |
Function |
2.3 全格式代码示例
java
public class Demo01 {
public static void main(String[] args) {
// 格式1:无参无返回值
Inter1 i1 = () -> {
System.out.println("马上该完事了!");
};
// 方法体只有一句,省略大括号
Inter1 i1_short = () -> System.out.println("马上该完事了!");
i1_short.test();
// 格式2:有一个参数,无返回值
Inter2 i2 = (x) -> System.out.println("你好" + x);
// 只有一个参数,小括号也可以省略!
Inter2 i2_short = x -> System.out.println("你好" + x);
i2_short.sayHi("苏澳");
// 格式3:多个参数,无返回值
Inter3 i3 = (x, y) -> System.out.println(x + y);
i3.printSum(10, 20); // 输出 30
// 格式4:有参有返回值(重点!⭐)
// 多条语句 → 大括号不能省略
Inter4 i4 = (x, y) -> {
double pow = Math.pow(x, y);
return pow;
};
// 只有一条 return 语句 → 省略大括号和 return,自动返回!
Inter4 i4_short = (x, y) -> Math.pow(x, y);
System.out.println(i4_short.getPow(2, 3)); // 8.0
}
}
interface Inter1 { void test(); }
interface Inter2 { void sayHi(String name); }
interface Inter3 { void printSum(int a, int b); }
interface Inter4 { double getPow(double a, double b); }
2.4 💡 省略规则记忆口诀
一句体 → 省大括号
一个参 → 省小括号
一句 return → 省大括号 + 省 return
多条语句 → 乖乖写全
三、函数式接口的校验 🔒
3.1 @FunctionalInterface 注解
java
@FunctionalInterface // ← 加上它,不是函数式接口就编译报错!
interface MyInterface {
void test(); // ✅ 只有一个抽象方法
// void test2(); // ❌ 再去掉注释看看?编译直接报错!
}
3.2 函数式接口的定义
| 条件 | 说明 |
|---|---|
| 只有一个抽象方法 ✅ | 可以有 default/static 方法,不算抽象 |
| 不加 @FunctionalInterface 也行 | 但加了编译器会帮你检查 |
四、Consumer<T> 消费型接口 💳
4.1 接口定义
Consumer<T>:消费型接口
📥 有输入(T 类型)
📤 无返回(void)
→ 只进不出,类似"花钱消费"
4.2 核心方法
| 方法 | 说明 |
|---|---|
void accept(T t) |
消费传入的数据,无返回值 |
4.3 代码示例:书源的按摩消费之路 💳
java
import java.util.function.Consumer;
public class ConsumerDemo {
public static void main(String[] args) {
// 消费规则1:踢脸服务
Consumer<Integer> con1 = m ->
System.out.println("书源享受踢脸服务,花费" + m + "元");
// 消费规则2:摸脸服务(升级版)
Consumer<Integer> con2 = m ->
System.out.println("书源到天上人间,享受苏澳摸脸服务,花费" + m + "元");
// 书源开始消费!
enjoyServer(10, con1); // 10块踢脸
enjoyServer(800, con2); // 800块摸脸
}
// 通用消费方法:传入金额 + 消费规则
public static void enjoyServer(int money, Consumer<Integer> consumer) {
consumer.accept(money); // 执行消费!
}
}
运行结果:
书源享受踢脸服务,花费10元
书源到天上人间,享受苏澳摸脸服务,花费800元
4.4 💡 Consumer 的典型场景
list.forEach(x -> System.out.println(x))→ forEach 就接收 Consumer!- 遍历集合、处理数据、打印日志
- 有入参,不需要返回值,就是 Consumer!
五、Supplier<T> 供给型接口 🏭
5.1 接口定义
Supplier<T>:供给型接口
📥 无输入
📤 有返回(T 类型)
→ 只出不进,类似"工厂生产"
5.2 核心方法
| 方法 | 说明 |
|---|---|
T get() |
无参,返回一个 T 类型结果 |
5.3 代码示例:苏澳的赚钱之路 🏭
java
import java.util.function.Supplier;
public class SupplierDemo {
public static void main(String[] args) {
// 挣钱方案1:卖银首饰
Supplier<Integer> s1 = () -> {
System.out.println("苏澳去卖银首饰");
return 3000;
};
// 挣钱方案2:踩缝纫机(包吃住)
Supplier<Integer> s2 = () -> {
System.out.println("苏澳踩缝纫机赚钱,每次1块,包吃住");
return 5;
};
// 统一获取收入
System.out.println("收入:" + getMoney(s1));
System.out.println("收入:" + getMoney(s2));
}
public static int getMoney(Supplier<Integer> supplier) {
return supplier.get(); // 从 Supplier 那里"拿"结果!
}
}
5.4 💡 Supplier 的典型场景
Optional.ofNullable(x).orElseGet(() -> defaultValue)→ 懒加载默认值- 工厂模式:根据规则生成对象
- 无参有返回值,就是 Supplier!
六、Function<T,R> 函数型接口 🔄️
6.1 接口定义
Function<T,R>:函数型接口
📥 有输入(T 类型)
📤 有返回(R 类型,可以和 T 不同类型)
→ 有进有出,数据转换器!
6.2 核心方法
| 方法 | 说明 |
|---|---|
R apply(T t) |
传入 T,返回 R |
andThen(Function after) ⭐ |
先执行自己,再执行 after,链式处理 |
6.3 代码示例:字符串处理链 🔄️
java
import java.util.function.Function;
public class FunctionDemo {
public static void main(String[] args) {
// 第1步:字符串 → 整数
Function<String, Integer> toInt = x -> Integer.parseInt(x);
// 第2步:整数 → 平方
Function<Integer, Integer> square = x -> x * x;
// andThen:先 toInt,结果交给 square 再处理!⭐
// "3" → 3 → 9
Integer result = toInt.andThen(square).apply("3");
System.out.println("3 的平方:" + result); // 9
}
}
💡 andThen 的作用:
toInt.andThen(square).apply("3")
等价于:
Integer temp = toInt.apply("3"); // "3" → 3
Integer result = square.apply(temp); // 3 → 9
6.4 💡 Function 的典型场景
- 数据转换:String → Integer、DTO → VO
- Stream 中的
map(x -> x.getName())→ 就是 Function! - 有进有出 → Function ✅
七、Predicate<T> 断言型接口 ⚖️
7.1 接口定义
Predicate<T>:断言型接口
📥 有输入(T 类型)
📤 返回 boolean(只能是 true/false)
→ 条件判断器!
7.2 核心方法
| 方法 | 说明 |
|---|---|
boolean test(T t) |
判断传入的参数 |
and(Predicate other) ⭐ |
逻辑与(&&) |
or(Predicate other) ⭐ |
逻辑或(||) |
negate() ⭐ |
取反(!) |
7.3 代码示例:多条件组合判断 ⚖️
java
import java.util.function.Predicate;
public class PredicateDemo {
public static void main(String[] args) {
// 判断1:字符串是否以 www 开头
Predicate<String> startsWithWww = x -> x.startsWith("www");
// 判断2:字符串是否以 xyz 结尾
Predicate<String> endsWithXyz = x -> x.endsWith("xyz");
// and:两个条件都满足 ✅
System.out.println(startsWithWww.and(endsWithXyz)
.test("www.baosy.xyz")); // true
// or:满足任意一个 ✅
Predicate<Integer> isZero = x -> x == 0;
Predicate<Integer> isOne = x -> x == 1;
System.out.println(isZero.or(isOne).test(1)); // true(是1)
// negate:取反 ✅
Predicate<Integer> isPositive = x -> x > 0;
System.out.println(isPositive.negate().test(3)); // false(3>0,取反)
}
}
7.4 💡 Predicate 的典型场景
- 校验参数:
x -> x != null、x -> x > 0 - Stream 中的
filter(x -> x > 10)→ 就是 Predicate! - 能组合 and/or/negate,写校验规则极其优雅 ✅
八、四大函数式接口速查表 📋
| 接口 | 输入 | 输出 | 核心方法 | 场景 |
|---|---|---|---|---|
| Consumer<T> 💳 | T | void | accept(T) |
遍历、消费数据 |
| Supplier<T> 🏭 | 无 | T | get() |
工厂、懒加载 |
| Function<T,R> 🔄️ | T | R | apply(T) / andThen |
数据转换 |
| Predicate<T> ⚖️ | T | boolean | test(T) / and/or/negate |
条件判断 |
九、方法引用------比 Lambda 更简洁 ✨
9.1 什么时候用方法引用?
Lambda 里面的内容,别人已经实现过了?
→ 直接用方法引用!不用重复写!
9.2 引用格式
| 格式 | 语法 | 示例 |
|---|---|---|
| 引用静态方法 | 类名 :: 静态方法名 |
Math::pow |
| 引用成员方法 | 对象名 :: 方法名 |
System.out::println |
| 引用构造方法 | 类名 :: new |
Person::new |
9.3 代码示例
java
public class MethodRefDemo {
public static void main(String[] args) {
// Lambda 写法
Inter6 i1 = x -> System.out.println(x);
// 方法引用(更简洁!✨)
Inter6 i2 = System.out::println;
i2.print("张三"); // 输出:张三
// Lambda:调用 Math.pow
Inter7 i3 = (x, y) -> Math.pow(x, y);
// 方法引用:直接引用 Math 的 pow 方法!
Inter7 i4 = Math::pow;
System.out.println(i4.getPow(10, 2)); // 100.0
}
}
interface Inter6 { void print(String name); }
interface Inter7 { double getPow(int a, int b); }
9.4 💡 方法引用的本质
任意一个方法 → 都可以当作「函数式接口的实现类对象」
方法引用 = 把方法当成数据来传递!
本篇总结 📝
- Lambda 表达式 🤔:匿名内部类的简化,前提是函数式接口
- 四种语法格式 🏗️:无参无反/有参无反/多参无返/有参有返(口诀助记)
- 函数式接口校验 🔒:
@FunctionalInterface注解,编译器帮你检查 - Consumer<T> 💳:
accept(T)只进不出,消费数据 - Supplier<T> 🏭:
get()只出不进,生产数据 - Function<T,R> 🔄️:
apply(T)+andThen()数据转换链 - Predicate<T> ⚖️:
test(T)+and/or/negate()组合判断 - 方法引用 ✨:
类::方法比 Lambda 更简洁,方法当数据传递!
🚀 下一篇预告:《四十六、Stream 流------集合操作的终极利器》------ 搞定 filter/map/reduce/collect,用流式思维优雅处理数据!
作者 :书源丶
发布平台:CSDN