Java中 Consumer 的用法:

简单理解:你给它一个东西,它负责 "消费 / 处理",不返回结果(比如打印、修改属性、保存数据等)。

一、先看核心定义

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 个 处理两个参数,无返回结果

核心特点

  1. 函数式接口 ,只能有一个抽象方法 accept()
  2. 有参数,无返回值
  3. 常用在:遍历、数据处理、属性修改、打印日志
  4. 支持 andThen() 链式处理
  5. 配合 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

相关推荐
做个文艺程序员2 小时前
Spring Boot 封装 OpenClAW 服务层最佳实践【OpenClAW + Spring Boot 系列 第2篇】
java·人工智能·spring boot·开源
说实话起个名字真难啊2 小时前
2026数字中国创新大赛数字安全赛道writeup之web题目一
java·前端·安全
后端AI实验室2 小时前
我用AI把一个外包需求从30天压到5天交付,然后客户说:下次还找你
java·ai
biubiubiu07062 小时前
ChatModel 与 ChatClient 关系完整指南
java
0xDevNull2 小时前
Java 深度解析:for 循环 vs Stream.forEach 及性能优化指南
java·开发语言·性能优化
博风3 小时前
在tomcat应用里添加了一个线程池对象,向这个线程池发送任务,让其执行。 我希望在tomcat停机时,能等待线程池里的任务执行完了再停机,要如何实现?
java·tomcat
studyForMokey3 小时前
【Android面试】Java专题 todo
android·java·面试
一只大袋鼠3 小时前
MyBatis 特性(三):缓存、延迟加载、注解开发
java·数据库·笔记·sql·缓存·mybatis
老毛肚3 小时前
Redis高级
java·数据库·redis