151. Java Lambda 表达式 - 使用 Consumer 接口处理对象

151. Java Lambda 表达式 - 使用 Consumer<T> 接口处理对象

Java 中,Consumer<T> 是一个非常重要的功能接口,它接受一个输入参数,但不返回任何结果。与 Supplier<T>(它不接受参数,返回结果)不同,Consumer<T> 专注于对传入的对象执行操作,而不关心返回值。

Consumer<T> 接口的定义

Consumer<T> 接口只有一个抽象方法 accept(T t),用于接受一个类型为 T 的参数并进行处理:

java 复制代码
@FunctionalInterface
public interface Consumer<T> {
    void accept(T t);
}
示例:使用 Consumer<String> 打印字符串
java 复制代码
Consumer<String> printer = s -> System.out.println(s);

这个 Consumer 实现接收一个字符串并将其打印到控制台。可以像这样使用它:

java 复制代码
for (int i = 0; i < 5; i++) {
    int nextRandom = newRandom.getAsInt();
    printer.accept("next random = " + nextRandom);
}

在这个示例中,我们使用 printer 来打印每次生成的随机数。

使用专用的 Consumer

Consumer<T> 接口的实现是通用的,但有时候我们需要处理原始类型数据(例如 intlongdouble),这时装箱(autoboxing)和拆箱(unboxing)会带来性能开销。为了优化性能,JDK 提供了专门的 Consumer 接口处理原始类型:IntConsumerLongConsumerDoubleConsumer

示例:使用 IntConsumer 打印整数
java 复制代码
Consumer<Integer> printer = i -> System.out.println(i);

这段代码使用 Consumer<Integer> 打印整数,但是,如果处理的是大量数据,自动装箱和拆箱可能会影响性能。因此,可以使用专用的 IntConsumer 接口来避免这种性能损失。

java 复制代码
IntConsumer intPrinter = i -> System.out.println(i);

IntConsumeraccept() 方法直接接受 int 类型,而不会进行装箱,因此效率更高。

使用 BiConsumer<T, U> 处理两个参数

除了接受单个参数的 Consumer<T>JDK 还提供了 BiConsumer<T, U> 接口,它可以同时接受两个参数,并对它们进行操作。它的定义如下:

java 复制代码
@FunctionalInterface
public interface BiConsumer<T, U> {
    void accept(T t, U u);
}
示例:使用 BiConsumer<Random, Integer> 打印多个随机数
java 复制代码
BiConsumer<Random, Integer> randomNumberPrinter = (random, number) -> {
    for (int i = 0; i < number; i++) {
        System.out.println("next random = " + random.nextInt());
    }
};

在上面的代码中,randomNumberPrinter 是一个 BiConsumer,它接受一个 Random 对象和一个整数 number,并打印出 number 个随机数。

调用这个 BiConsumer

java 复制代码
randomNumberPrinter.accept(new Random(314L), 5);

输出示例:

java 复制代码
next random = 1
next random = 5
next random = 3
next random = 0
next random = 2

专用的 BiConsumer 接口

Consumer<T> 类似,BiConsumer<T, U> 也有专门的版本,处理原始类型数据,避免装箱和拆箱的开销。它们包括:

  • ObjIntConsumer<T>:接受一个对象和一个 int
  • ObjLongConsumer<T>:接受一个对象和一个 long
  • ObjDoubleConsumer<T>:接受一个对象和一个 double

这些专用接口与 BiConsumer 的工作方式相同,但它们通过避免不必要的装箱来提高性能。

Consumer 传递给 Iterable

Iterable 接口的 forEach() 方法是另一个与 Consumer<T> 紧密结合的地方。forEach() 方法接受一个 Consumer<T> 并对 Iterable 中的每个元素执行操作。这使得对集合的处理更加简洁和高效。

示例:使用 forEach() 遍历列表并打印元素
java 复制代码
List<String> strings = List.of("Java", "Lambda", "Consumer");
Consumer<String> printer = s -> System.out.println(s);
strings.forEach(printer);

在这个例子中,strings.forEach(printer) 会遍历列表 strings,并将 printer Consumer 应用于每个元素,将其打印出来。

输出示例:
java 复制代码
Java
Lambda
Consumer

forEach() 方法提供了一种简单的方式来处理 Iterable 中的每个元素。不再需要手动编写循环语句,代码更加简洁和易于理解。

总结

  • Consumer<T> 接口Consumer<T> 接口用于接受一个对象并对其执行操作,但不返回任何值。它通常用于打印、修改或消费数据。
  • 专用 Consumer 接口 :为了避免装箱和拆箱带来的性能损失,JDK 提供了专用的 IntConsumerLongConsumerDoubleConsumer 接口处理原始类型。
  • BiConsumer<T, U> 接口BiConsumer 接口允许同时处理两个参数,并执行操作。它在需要处理两个输入时非常有用。
  • forEach() 方法forEach() 方法与 Consumer<T> 接口结合使用,提供了一种简单的方式来遍历 Iterable 并对每个元素执行操作。

通过理解并使用这些接口,可以在 Java 中编写更简洁、易读且高效的代码。

相关推荐
架构师沉默3 分钟前
Java 开发者别忽略 return!这 11 种写法你写对了吗?
java·后端·架构
li理3 分钟前
鸿蒙 Next 布局开发实战:6 大核心布局组件全解析
前端
EndingCoder5 分钟前
React 19 与 Next.js:利用最新 React 功能
前端·javascript·后端·react.js·前端框架·全栈·next.js
li理7 分钟前
鸿蒙 Next 布局大师课:从像素级控制到多端适配的实战指南
前端
RainbowJie110 分钟前
Gemini CLI 与 MCP 服务器:释放本地工具的强大潜力
java·服务器·spring boot·后端·python·单元测试·maven
前端赵哈哈11 分钟前
Vite 图片压缩的 4 种有效方法
前端·vue.js·vite
Nicholas6818 分钟前
flutter滚动视图之ScrollView源码解析(五)
前端
电商API大数据接口开发Cris19 分钟前
Go 语言并发采集淘宝商品数据:利用 API 实现高性能抓取
前端·数据挖掘·api
ITMan彪叔20 分钟前
Nodejs打包 Webpack 中 __dirname 的正确配置与行为解析
javascript·后端
风中凌乱的L25 分钟前
vue 一键打包上传
前端·javascript·vue.js