转换Guava可选的函数可能返回null

时间:2018-01-24 21:59:52

标签: java guava optional

TL; DR

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

奖金问题:如果变换器函数返回NPE,那么以番石榴方式存在一个优势,即抛出null? (而不是像Java 8 Optional.absent()那样将其转换为Optional。或者它只是设计的缺点?

问题

根据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. 选中if/else,使用ifPresent。问题:有点杀死了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()));
    

1 个答案:

答案 0 :(得分:3)

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

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

    你可以使用它们让java.util.Optional在你的Optional.map方法中使用一个函数来调用你的方法,应用它自己的语义(如果函数返回{它不会抛出NullPointerException { {1}},但改为空null。然后,如果您需要,请通过java.util.Optional方法将此映射的java.util.Optional转换回番石榴Optional

    以下是显示此方法的代码:

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

    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();
        }
    }