Java Supplier接口

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 方法将返回一个 OptionalOptional 要么包含所需的元素,要么为空。在本例中,由于列表中的任何名称都不会传递给筛选器,所以结果是一个空 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创建日志消息 )。
赞(5)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

Java 实例