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> 接口的实现是通用的,但有时候我们需要处理原始类型数据(例如 int、long、double),这时装箱(autoboxing)和拆箱(unboxing)会带来性能开销。为了优化性能,JDK 提供了专门的 Consumer 接口处理原始类型:IntConsumer、LongConsumer 和 DoubleConsumer。

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

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

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

IntConsumer 的 accept() 方法直接接受 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 提供了专用的 IntConsumer、LongConsumer 和 DoubleConsumer 接口处理原始类型。
  • BiConsumer<T, U> 接口 :BiConsumer 接口允许同时处理两个参数,并执行操作。它在需要处理两个输入时非常有用。
  • forEach() 方法 :forEach() 方法与 Consumer<T> 接口结合使用,提供了一种简单的方式来遍历 Iterable 并对每个元素执行操作。

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

相关推荐
itmigrate2 小时前
前端项目里,Object.is 并不是 === 的平替
前端
喵了几个咪3 小时前
GoWind CMS 拆解:在 Go 里给 TipTap 搭一套 Yjs 协同后端
开发语言·后端·golang
Flynt3 小时前
我把微信运动的排行榜和定点推送复刻了一遍:100万次步数更新只要4秒,坑在别处
redis·后端·性能优化
小大宇4 小时前
Vue知识点6-computed计算属性
前端·javascript·vue.js
程序员海军4 小时前
尤雨溪 : Vue 4 已经在规划中了!
前端·javascript·vue.js
2601_949970694 小时前
HumanizeDuration 跨端三方库仓颉适配全流程
前端·javascript·flutter
_孤傲_5 小时前
快速掌握 MySQL 语法
数据库·后端·mysql
风骏时光牛马6 小时前
后端服务接口开发与性能优化
前端
kyriewen6 小时前
我让 4 个 AI 互相 review 代码,最温柔的那个下手最狠
前端·程序员·ai编程
计算机魔术师6 小时前
493家公司白砸AI钱?Apollo这组数据戳破了幻觉
前端