Java Supplier接口,用户希望实现 java.util.function.Supplier 接口,可以使用 lambda 表达式或方法引用来实现 T get() 方法。Supplier 接口相当简单,它不包含任何静态或默认方法,只有一个抽象方法 T get()。为实现 Supplier 接口,需要提供一个不传入参数且返回泛型类型(generic type)的方法。根据 Javadoc 的描述,调用 Supplier 时,不要求每次都返回一个新的或不同的结果。
Java Supplier接口 问题描述
用户希望实现 java.util.function.Supplier 接口。
Java Supplier接口 解决方案
使用 lambda 表达式或方法引用来实现 T get() 方法。
Java Supplier接口 具体实例
Supplier 接口相当简单,它不包含任何静态或默认方法,只有一个抽象方法 T get()。
为实现 Supplier 接口,需要提供一个不传入参数且返回泛型类型(generic type)的方法。根据 Javadoc 的描述,调用 Supplier 时,不要求每次都返回一个新的或不同的结果。
Supplier 的一种简单应用是 Math.random 方法,它不传入参数且返回 double 型数据。如例 2-4 所示,Math.random 方法可以被赋给 Supplier 引用并随时调用。
例 2-4 使用
Math.random作为Supplier
Logger logger = Logger.getLogger("...");
DoubleSupplier randomSupplier = new DoubleSupplier() { ➊
@Override
public double getAsDouble() {
return Math.random();
}
};
randomSupplier = () -> Math.random(); ➋
randomSupplier = Math::random; ➌
logger.info(randomSupplier);
❶ 匿名内部类实现
❷ lambda 表达式
❸ 方法引用
DoubleSupplier 接口包含的单一抽象方法为 getAsDouble,它返回一个 double 型数据。表 2-2 列出了 java.util.function 包定义的其他相关 Supplier 接口。
表2-2:其他Supplier接口
| 接口 | 单一抽象方法 |
|---|---|
IntSupplier |
int getAsInt() |
DoubleSupplier |
double getAsDouble() |
LongSupplier |
long getAsLong() |
BooleanSupplier |
boolean getAsBoolean() |
Supplier 的一个主要用例是延迟执行(deferred execution)。java.util.logging.Logger 类定义的 info 方法传入 Supplier,仅当日志级别(log level)控制日志消息可见时,才调用其 get 方法(详见范例利用Supplier创建日志消息 )。用户可以在自己的代码中应用延迟执行,以确保只在合适的情况下才从 Supplier 中检索值。
另一个用例是标准库中 java.util.Optional 类定义的 orElseGet 方法,它同样传入 Supplier。
有关 Optional 类的讨论请参见Optional的创建 ,不过简而言之,Optional 类是一种容器对象(container object),要么包装值,要么为空。Optional 类通常用于在返回值可能合法为 null 时与用户进行通信,比如在空集中查找某个值。
我们以在一个集合中搜索名称为例,展示以上方法的应用,如例 2-5 所示。
例 2-5 在集合中查找名称
List<String> names = Arrays.asList("Mal", "Wash", "Kaylee", "Inara",
"Zoë", "Jayne", "Simon", "River", "Shepherd Book");
Optional<String> first = names.stream()
.filter(name -> name.startsWith("C"))
.findFirst();
System.out.println(first); ➊
System.out.println(first.orElse("None")); ➋
System.out.println(first.orElse(String.format("No result found in %s",
names.stream().collect(Collectors.joining(", "))))); ➌
System.out.println(first.orElseGet(() ->
String.format("No result found in %s",
names.stream().collect(Collectors.joining(", "))))); ➍
❶ 打印 Optional.empty
❷ 打印字符串 "None"
❸ 即便找到指定的名称,仍然使用逗号分隔集合
❹ 仅当 Optional 为空时,才使用逗号分隔集合
Stream 接口的 findFirst 方法将返回有序流中出现的第一个元素。2 由于可以将流中的元素全部滤掉,findFirst 方法将返回一个 Optional。Optional 要么包含所需的元素,要么为空。在本例中,由于列表中的任何名称都不会传递给筛选器,所以结果是一个空 Optional。
2流可能存在(也可能不存在)出现顺序,如同列表被假定为按索引排序而集合不是。这与元素的处理顺序可能有所不同。详见范例 查找流的第一个元素 。
Optional 类的 orElse 方法可以返回包含的元素,或者可以返回指定的默认值。虽然默认值为简单的字符串并无不妥,但如果需要经过处理才能返回值,则简单字符串的意义不大。
在本例中,返回值以逗号分隔的形式显示了名称的完整列表。无论 Optional 中是否包含值,orElse 方法都会创建完整的字符串。
而 orElseGet 方法传入 Supplier 作为参数。其优点在于,仅当 Optional 为空时,才会调用 Supplier 接口的 get 方法。换言之,除非确有必要,否则不会创建完整的名称字符串。
标准库还支持 Supplier 接口的其他一些用法。
Optional类的orElseThrow方法传入Supplier<X extends Exception>,仅当发生异常时才会执行Supplier。- 当
Objects.requireNonNull(T obj, Supplier<String> messageSupplier)的第一个参数为空时,抛出自定义的NullPointerException。 CompletableFuture.supplyAsync(Supplier<U> supplier)返回一个CompletableFuture,它通过调用给定Supplier获得的值,以使得运行的任务异步完成。Logger类的所有日志记录方法都有相应的重载形式,它传入Supplier<String>,而不仅仅是一个字符串(详见范例利用Supplier创建日志消息 )。
极客教程