150. Java Lambda 表达式 - Supplier 接口
Java SE 8 引入了 Lambda 表达式,并对 JDK API 进行了重写,使得 Lambda 能够与现有代码良好集成。引入 Lambda 表达式后,JDK 8 更新的类比 JDK 5 中引入泛型后的更新更多。这使得 Lambda 表达式可以广泛应用于应用程序中,并通过简洁的语法实现功能。
JDK 8 引入的 java.util.function 包
在 JDK 8 中,除了 Lambda 表达式外,java.util.function 包也得到了引入,这个包包含了大量的功能接口,这些接口在 JDK API 中被广泛使用,尤其是在集合框架(Collections Framework)和流 API(Stream API)中。该包位于 java.base 模块中,提供了超过 40 个接口,初看之下可能让人感到有些困惑,但它们围绕着四个主要接口进行组织,了解这些主要接口能够帮助我们理解其他功能接口。
生产者(提供者)接口:Supplier<T>
Supplier<T> 是 java.util.function 包中的第一个接口,它的功能是提供一个对象。简单来说,Supplier<T> 接口不接受任何参数,但返回一个对象。Lambda 表达式可以用来实现 Supplier 接口。
Supplier<T> 接口的定义
@FunctionalInterface
public interface Supplier<T> {
T get();
}
示例:使用 Supplier<String> 创建一个返回字符串的 Lambda 表达式
Supplier<String> supplier = () -> "Hello Duke!";
System.out.println(supplier.get()); // 输出 "Hello Duke!"
这个 Lambda 表达式简单地返回了 "Hello Duke!" 字符串。可以在实际应用中使用不同的 Supplier 实现来动态生成或提供不同的对象。
示例:使用 Supplier 生成随机数
Random random = new Random(314L);
Supplier<Integer> newRandom = () -> random.nextInt(10);
for (int index = 0; index < 5; index++) {
System.out.println(newRandom.get() + " ");
}
在上面的示例中,newRandom 是一个 Supplier<Integer>,每次调用它的 get() 方法时,会生成一个随机数。由于随机数生成器的种子(314L)固定,因此生成的随机数是可预测的。
输出示例:
1
5
3
0
2
注意,在这个例子中,Lambda 表达式从外部作用域捕获了 random 变量。由于 random 是不可变的,它符合 Lambda 表达式的要求,即只能捕获 final 或实际是 final 的变量。
使用 Supplier<T> 接口
可以通过调用 get() 方法来获取 Supplier 提供的对象。例如:
for (int index = 0; index < 5; index++) {
System.out.println(newRandom.get() + " ");
}
每次调用 get() 方法都会执行 Lambda 表达式中的代码,生成并返回一个新的随机数。
使用专用的生产者接口
为了提高性能,避免不必要的装箱(autoboxing)和拆箱(unboxing),JDK 8 提供了 Supplier<T> 接口的专用优化版本,用于处理原始类型。这些专用版本的接口可以避免装箱和拆箱的开销,因此在需要优化性能时尤为有用。
JDK 8 提供了以下几种专用的 Supplier 接口:
IntSupplier:返回int类型的值。LongSupplier:返回long类型的值。DoubleSupplier:返回double类型的值。BooleanSupplier:返回boolean类型的值。
示例:使用 IntSupplier 生成随机整数
Random random = new Random(314L);
IntSupplier newRandom = () -> random.nextInt();
for (int i = 0; i < 5; i++) {
int nextRandom = newRandom.getAsInt();
System.out.println("next random = " + nextRandom);
}
这里,我们使用 IntSupplier 来避免不必要的装箱。与 Supplier<Integer> 不同,IntSupplier 返回的是原始类型 int,因此没有发生装箱和拆箱,性能更高。
输出示例:
next random = 1
next random = 5
next random = 3
next random = 0
next random = 2
专用 Supplier 接口的优势
通过使用专用的供应商接口(如 IntSupplier、LongSupplier、DoubleSupplier 和 BooleanSupplier),可以在不进行装箱/拆箱的情况下处理原始类型数据。这样能够避免不必要的性能开销,特别是在性能要求较高的场景下,减少 CPU 周期的消耗。
总结
Lambda表达式与java.util.function包:Lambda表达式与java.util.function包中的接口紧密结合,为开发者提供了简单而强大的工具来处理函数式编程任务。Supplier<T>接口:用于生成对象,Supplier不接受参数,只返回一个对象。可以使用它来动态生成和提供对象,如生成随机数等。- 专用
Supplier接口:为了提高性能,避免装箱/拆箱操作,JDK提供了专门的接口(如IntSupplier、LongSupplier等)来处理原始类型。
通过理解和掌握这些概念,可以在 Java 中更高效地使用 Lambda 表达式,并根据需要选择合适的接口来优化性能。