【问题标题】:Tranforming Guava Optional with function that might return null使用可能返回 null 的函数转换 Java Optional
【发布时间】:2018-07-04 01:58:10
【问题描述】:

TL;DR

使用可能返回 null 的函数,transform 使用 Guava Optional 的最佳(即最紧凑/可读)方式是什么? (所以在这种情况下,我们应该得到一个Optional.absent(),而不是一个 NPE。)

额外问题:如果转换器函数返回null,则在 Guava 方式中是否有优势,即抛出 NPE? (而不是将其转换为 Optional.absent(),就像在 Java 8 的情况下 Optionals 一样。)或者这只是设计的一个缺点?

问题

根据documentation of Guava Optional.transform

与 java.util.Optional 的比较:此方法类似于 Java 8 的 Optional.map,除非函数返回 null。在这种情况下 方法抛出异常,而 Java 8 方法返回 Optional.absent().

示例

以下函数对两个示例都是通用的:

public String methodThatMighReturnNull(boolean returnNull, Integer input) {
    return returnNull ? null : String.valueOf(input);
}

对于 Java 8,这不会引发 NPE,而是返回一个空的 Optional

Optional<Integer> input = Optional.of(42);
Optional<String> result = input.map(new Function<Integer, String>() {
    public String apply(Integer input) {
        return methodThatMighReturnNull(true, input);
    }
});

以下与 Guava 类似的代码会引发 NPE:

Optional<Integer> input = Optional.of(42);
Optional<String> result = input.transform(new Function<Integer, String>() {
    public String apply(Integer input) {
        return methodThatMighReturnNull(true, input);
    }
});

可能的替代方案

我已经找到/考虑了一些替代方案,但如下所述,所有替代方案都有问题:

  1. 将返回值包装成Optional。问题:太繁琐,更难阅读;

    Optional<Integer> input = Optional.of(42);
    Optional<String> result = input.transform(new Function<Integer, Optional<String>>() {
        public Optional<String> apply(Integer input) {
            return fromNullable(methodThatMighReturnNull(true, input));
        }
    }).get();
    
  2. 通过检查ifPresent 使用if/else。问题:有点扼杀Optional 的意义。 (我们可以只使用引用并检查 null。)

    Optional<Integer> input = Optional.of(42);
    Optional<String> result;
    if (input.isPresent()) {
        result = fromNullable(methodThatMighReturnNull(true, input.get()));
    } else {
        result = Optional.absent();
    }
    
  3. 只需应用该函数,并将其包装在fromNullable 中。 (如在GitHub 上找到的,似乎已经提出了相同的问题。)问题:这与原始示例略有不同。在这种情况下,methodThatMighReturnNull 最终可能会收到null,而在最初的情况下这是不可能的。

    Optional<Integer> input = Optional.of(42);
    Optional<String> result;
    result = fromNullable(new Function<Integer, String>() {
        public String apply(Integer input) {
            return methodThatMighReturnNull(true, input);
        }
    }.apply(input.orNull()));
    

【问题讨论】:

  • Java 8+ 中的 Guava 代码? Lambdas 将使 #1 和 #3 更可口。
  • 更实用的方法是使用flatMap() 来确保您始终映射到正确的范围。
  • 这是哪个版本的 Java?

标签: java guava optional


【解决方案1】:

除了您在问题中列出的替代方案外,还有其他两种可能性:

  1. 如果您使用的是 Java 8 或更高版本,从 Guava 21.0 开始,您有 Optional.toJavaUtil() 实例方法,它将您的 Guava Optional 实例转换为 java.util.Optional 实例,还有 Optional.fromJavaUtil 静态方法,它从 java.util.Optional 一个实例创建一个 Guava Optional 实例。

    您可以使用它们让java.util.Optional 采用在其Optional.map 方法中调用您的方法的函数,应用它自己的语义(如果函数返回NullPointerException,它不会抛出NullPointerException,而是一个空的java.util.Optional 代替)。然后,如果您需要,可以通过 Optional.fromJavaUtil 方法将此映射的 java.util.Optional 转换回 Guava Optional

    下面是展示这种方法的代码:

    Optional<Integer> input = Optional.of(42);
    java.util.Optional<String> temp = input.toJavaUtil()
        .map(i -> methodThatMighReturnNull(true, i));
    Optional<String> result = Optional.fromJavaUtil(temp);
    
  2. 如果您还没有使用 Java 8 或更高版本(或者如果您使用但不喜欢以前的方法),我会选择您的第二个替代方案的变体。为此,我将使用您需要的语义实现 transformNullSafe 方法:

    public static <T, R> Optional<R> transformNullSafe(
            Optional<T> optional,
            Function<T, R> function) {
    
        if (optional.isPresent()) {
            return Optional.fromNullable(function.apply(optional.get()));
        } else {
            return Optional.absent();
        }
    }
    

    用法:

    Optional<Integer> input = Optional.of(42);
    Optional<String> result = transformNullSafe(
        input, 
        new Function<Integer, String>() {
            public String apply(Integer i) {
                return methodThatMighReturnNull(true, i);
            }
        });
    

【讨论】:

  • 特别感谢您将我指向toJavaUtil()。我不知道它的存在。
猜你喜欢
  • 2019-07-20
  • 2013-09-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-05-24
  • 2019-06-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多