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创建日志消息 )。