简单理解:你给它一个东西,它负责 "消费 / 处理",不返回结果(比如打印、修改属性、保存数据等)。
一、先看核心定义
java
运行
csharp
@FunctionalInterface
public interface Consumer<T> {
// 唯一的抽象方法:接收一个参数,无返回值
void accept(T t);
}
- 只有一个抽象方法
accept(T t) - 专门用来做有参数、无返回值的操作
- 配合 Lambda 表达式、方法引用使用
二、最基础用法(必看)
1. 匿名内部类(老式写法)
java
运行
typescript
import java.util.function.Consumer;
public class ConsumerTest {
public static void main(String[] args) {
// 定义一个Consumer:接收字符串,打印它
Consumer<String> printConsumer = new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println("消费了:" + s);
}
};
// 使用
printConsumer.accept("Hello Consumer");
}
}
2. Lambda 简化(推荐写法)
java
运行
typescript
public class ConsumerTest {
public static void main(String[] args) {
// Lambda 一行搞定
Consumer<String> printConsumer = s -> System.out.println("消费了:" + s);
printConsumer.accept("Java 8 真香");
}
}
3. 方法引用再简化
java
运行
ini
Consumer<String> printConsumer = System.out::println;
printConsumer.accept("方法引用版");
三、最常用场景:集合遍历
Java 集合的 forEach() 方法参数就是 Consumer,这是你最常用到的地方!
java
运行
java
import java.util.Arrays;
import java.util.List;
public class ConsumerTest {
public static void main(String[] args) {
List<String> list = Arrays.asList("张三", "李四", "王五");
// forEach 接收的就是 Consumer!
list.forEach(s -> System.out.println("姓名:" + s));
// 简化写法
list.forEach(System.out::println);
}
}
四、高级用法:andThen 链式消费
Consumer 自带默认方法 andThen(Consumer after):先执行当前消费,再执行后面的消费,链式调用。
java
运行
typescript
public class ConsumerTest {
public static void main(String[] args) {
// 第一个Consumer:转大写
Consumer<String> upperConsumer = s -> System.out.println(s.toUpperCase());
// 第二个Consumer:拼接字符串
Consumer<String> concatConsumer = s -> System.out.println(s + " - 处理完成");
// andThen 链式执行:先大写,再拼接
upperConsumer.andThen(concatConsumer).accept("hello");
}
}
输出:
plaintext
HELLO
hello - 处理完成
五、实战例子:处理对象(最实用)
处理用户对象,比如打印信息、修改属性。
1. 定义实体类
java
运行
arduino
class User {
private String name;
private int age;
// 构造、get、set、toString
public User(String name, int age) {
this.name = name;
this.age = age;
}
public void setAge(int age) { this.age = age; }
@Override
public String toString() { return name + ",年龄:" + age; }
}
2. 使用 Consumer 处理 User
java
运行
typescript
public class ConsumerTest {
public static void main(String[] args) {
User user = new User("小明", 20);
// 1. 打印用户信息
Consumer<User> printUser = u -> System.out.println("用户信息:" + u);
// 2. 修改年龄
Consumer<User> updateAge = u -> u.setAge(25);
// 先修改,再打印
updateAge.andThen(printUser).accept(user);
}
}
输出:
plaintext
用户信息:小明,年龄:25
六、封装工具方法(通用处理)
把 Consumer 当作参数传入方法,实现通用处理逻辑,代码更灵活。
java
运行
csharp
public class ConsumerTest {
// 通用方法:接收一个值 + 一个处理器(Consumer)
public static <T> void process(T data, Consumer<T> consumer) {
System.out.println("开始处理数据...");
consumer.accept(data); // 交给Consumer处理
System.out.println("处理完成\n");
}
public static void main(String[] args) {
// 处理字符串
process("测试数据", s -> System.out.println("字符串内容:" + s));
// 处理数字
process(100, i -> System.out.println("数字平方:" + i * i));
// 处理对象
process(new User("小红", 18), u -> System.out.println("用户:" + u));
}
}
七、BiConsumer(扩展:两个参数)
如果需要接收两个参数 ,用 BiConsumer<T, U>,用法几乎一样。
java
运行
typescript
import java.util.function.BiConsumer;
public class ConsumerTest {
public static void main(String[] args) {
// 接收两个参数:姓名 + 年龄,打印
BiConsumer<String, Integer> biConsumer = (name, age) ->
System.out.println("姓名:" + name + ",年龄:" + age);
biConsumer.accept("小李", 22);
}
}
八、核心总结(一句话记住)
表格
| 接口 | 参数 | 返回值 | 用途 |
|---|---|---|---|
Consumer |
1 个 | 无 | 处理一个参数,无返回结果 |
BiConsumer |
2 个 | 无 | 处理两个参数,无返回结果 |
核心特点
- 函数式接口 ,只能有一个抽象方法
accept() - 有参数,无返回值
- 常用在:遍历、数据处理、属性修改、打印日志
- 支持
andThen()链式处理 - 配合 Lambda / 方法引用,代码极简
九、实战:
1、HomeActivity调用:
scala
public class HomeActivity extends FragmentActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home);
TextView countdown = findViewById(R.id.countdown);
countdown.setOnClickListener(v -> {
// 使用
RunContainerManager.getContainerCallbacks().forEach(callback -> {
// 这里传入实际的 Fragment 实例,假设我们创建了一个新的 Fragment 实例
//callback.accept(new Fragment()); // 这里传入实际的 Fragment 实例
callback.accept(MyFragment.this);
});
});
}
}
2、RunContainerManager公共方法:
swift
public class RunContainerManager {
private static final List<Consumer<Fragment>> runContainerCallbacks = new ArrayList<>();
public static void registerContainerCallback(Consumer<Fragment> callback) {
if (!runContainerCallbacks.contains(callback)) {
runContainerCallbacks.add(callback);
}
}
public static List<Consumer<Fragment>> getContainerCallbacks() {
return runContainerCallbacks;
}
}
3、InitStartupTask启动类:
scss
//startup任务,app启动时会执行这个类的静态代码块,注册容器回调
public class InitStartupTask {
static {
// 初始化时注册容器回调
try {
registerContainerCallback();
} catch (Exception e) {
Log.e("lyy", "Failed to register container callback", e);
}
}
private static void registerContainerCallback() {
//调用Consumer 接口,注册回调,相当于 new Consumer<Fragment>() ,并把这个fragment传入到registerContainerCallback(Consumer<Fragment> callback)回调中
RunContainerManager.registerContainerCallback(container -> {
//通过Arouter获取IRunProvider实例,getRunTabContent()的变化
IRunProvider runProvider = (IRunProvider) ARouter.getInstance().build(RouterURL.Provider.RUN_API).navigation();
runProvider.getRunTabContent().observe(container.getViewLifecycleOwner(), pair -> {
TabBean detailBean = pair.first;
OrderBean orderBean = pair.second;
if (orderBean instanceof VideoBean) {
//视频页(路由跳转)
NavigationHelper.popUpNavigate(container.getView(), R.id.car_fragment_video);
} else if (orderBean instanceof OrderPageBean) {
//订单页(路由跳转)
NavigationHelper.popUpNavigate(container.getView(), R.id.car_fragment_order);
}
});
});
}
}
十、核心解析:
1、我先把你的代码 "还原成老式写法",你瞬间看懂:
ini
RunContainerManager.registerContainerCallback(container -> {
});
2、 还原成完整匿名内部类(一眼看到参数)
java
运行
typescript
// 这里创建了一个 Consumer<Fragment> 对象
Consumer<Fragment> callback = new Consumer<Fragment>() {
@Override
public void accept(Fragment container) { // <-- 这里就是参数!!!
// 你的逻辑
}
};
// 然后把 callback 传进去!!
RunContainerManager.registerContainerCallback(callback);
3、 核心真相:
container -> { ... }
等价于 → new Consumer() 重写 accept 方法
4、 为什么没有传参数 Consumer callback?
答案:
** 你传了!
container -> { ... } 整个这一大段,就是参数 callback 本身!**
再给你看一眼方法定义,你彻底闭环
java
运行
typescript
public static void registerContainerCallback(Consumer<Fragment> callback) {
}
你调用:
java
运行
scss
registerContainerCallback( container -> { ... } );
container -> { ... }→ 就是Consumer<Fragment>- 完全匹配参数
- 语法正确
- 逻辑正确
最后总结(你一定能听懂)
Lambda 表达式 = 隐形的 Consumer
你写的那段代码,就是完整的 Consumer 参数,只是写法太简洁,让你误以为没传参。
十一、callback.accept(MyContainerFragment.this); 含义?
我用最直白、最彻底、一步都不跳过 的方式给你讲懂,保证你马上通透!
一句话终极解释
java
运行
kotlin
callback.accept(MyContainerFragment.this);
意思就是:把当前这个 Fragment 对象,传给 "提前注册好的那段 Lambda 代码",并让它立刻执行!
1. 先回忆:callback 是什么?
callback = 你之前注册的:
java
运行
rust
container -> {
// 你的逻辑:监听Tab、跳转页面...
}
它就是一个 Consumer
2. accept(...) 是什么?
这是 Consumer 唯一的方法:
java
运行
arduino
void accept(Fragment fragment);
作用:把一个 Fragment 对象 "喂" 给这段 Lambda,让它执行。
3. MyContainerFragment.this 是什么?
就是 当前 Fragment 自己 也就是已经创建好的 View 容器
4. 合在一起的真正意思
java
运行
kotlin
callback.accept(MyContainerFragment.this);
翻译成人话:
喂!你之前不是说等 Fragment 创建好了要执行一段代码吗?现在 Fragment 已经创建好了(就是我自己),你可以拿着我去执行你的逻辑了!
5. 最直观的对应关系(你一看就懂)
java
运行
kotlin
// 你注册的 Lambda
container -> {
// 这里的 container
// 就是 accept 传进来的 CarContainerFragment.this
}
// 调用
callback.accept(CarContainerFragment.this);
箭头对应:
CarContainerFragment.this 会自动变成Lambda 里的 container