Optional orElse Optional

2023/07/03

1. 概述

在某些情况下,如果另一个Optional实例为空,我们可能希望回退到另一个Optional实例。

在本教程中,我们将简要介绍如何做到这一点-这比看起来要难。

有关Java Optional类的介绍,请查看我们之前的文章

2. Java 8

在Java 8中,如果第一个为空,则没有直接的方法来实现返回不同的Optional

因此,我们可以实现自己的自定义方法:

public static <T> Optional<T> or(Optional<T> optional, Optional<T> fallback) {
    return optional.isPresent() ? optional : fallback;
}

并且测试:

@Test
public void givenOptional_whenValue_thenOptionalGeneralMethod() {
    String name = "Filan Fisteku";
    String missingOptional = "Name not provided";
    Optional<String> optionalString = Optional.ofNullable(name);
    Optional<String> fallbackOptionalString = Optional.ofNullable(missingOptional);
 
    assertEquals(optionalString, Optionals.or(optionalString, fallbackOptionalString));
}
    
@Test
public void givenEmptyOptional_whenValue_thenOptionalGeneralMethod() {
    Optional<String> optionalString = Optional.empty();
    Optional<String> fallbackOptionalString = Optional.ofNullable("Name not provided");
 
    assertEquals(fallbackOptionalString, Optionals.or(optionalString, fallbackOptionalString));
}

2.1 惰性评估

上面的解决方案有一个严重的缺点-我们需要在使用我们的自定义or()方法之前评估两个Optional变量

想象一下,我们有两个返回Optional的方法,都在后台查询数据库。从性能的角度来看,如果第一个方法已经返回了我们需要的值,那么同时调用这两个方法是不可接受的。

让我们创建一个简单的ItemsProvider类:

public class ItemsProvider {
    public Optional<String> getNail() {
        System.out.println("Returning a nail");
        return Optional.of("nail");
    }

    public Optional<String> getHammer() {
        System.out.println("Returning a hammer");
        return Optional.of("hammer");
    }
}

以下是我们如何链接这些方法并利用惰性求值

@Test
public void givenTwoOptionalMethods_whenFirstNonEmpty_thenSecondNotEvaluated() {
    ItemsProvider itemsProvider = new ItemsProvider();

    Optional<String> item = itemsProvider.getNail()
        .map(Optional::of)
        .orElseGet(itemsProvider::getHammer);

    assertEquals(Optional.of("nail"), item);
}

上面的测试用例只打印了“Returning a nail”,这清楚地表明只执行了getNail()方法。

3. Java 9

Java 9添加了一个or()方法,如果Optional不存在,我们可以使用它来获取Optional或另一个值

让我们通过一个简单的例子在实践中看到这一点:

public static Optional<String> getName(Optional<String> name) {
    return name.or(() -> getCustomMessage());
}

我们使用了一个辅助方法来帮助我们完成示例:

private static Optional<String> getCustomMessage() {
    return Optional.of("Name not provided");
}

我们可以对其进行测试并进一步了解其工作原理,下面的测试用例是Optional有值时的演示:

@Test
public void givenOptional_whenValue_thenOptional() {
    String name = "Filan Fisteku";
    Optional<String> optionalString = Optional.ofNullable(name);
    assertEquals(optionalString, Optionals.getName(optionalString));
}

4. 使用Guava

另一种方法是使用Guava Optional类的or()方法。首先,我们需要在我们的项目中添加Guava(最新版本可以在这里找到):

<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>31.0.1-jre</version>
</dependency>

现在,我们可以继续之前的相同示例:

public static com.google.common.base.Optional<String> getOptionalGuavaName(com.google.common.base.Optional<String> name) {
    return name.or(getCustomMessageGuava());
}

private static com.google.common.base.Optional<String> getCustomMessageGuava() {
    return com.google.common.base.Optional.of("Name not provided");
}

正如我们所看到的,它与上面显示的非常相似。但是,它在方法的命名上略有不同,与JDK 9中Optional类的or()方法完全相同。

我们现在可以测试它,类似于上面的例子:

@Test
public void givenGuavaOptional_whenInvoke_thenOptional() {
    String name = "Filan Fisteku";
    Optional<String> stringOptional = Optional.of(name);
 
    assertEquals(name, Optionals.getOptionalGuavaName(stringOptional));
}

@Test
public void givenGuavaOptional_whenNull_thenDefaultText() {
    assertEquals(
        com.google.common.base.Optional.of("Name not provided"), 
        Optionals.getOptionalGuavaName(com.google.common.base.Optional.fromNullable(null)));
}

5. 总结

这是一篇简短的文章,说明了如何实现Optional或Else Optional的功能。

与往常一样,本教程的完整源代码可在GitHub上获得。

Show Disqus Comments

Post Directory

扫码关注公众号:Taketoday
发送 290992
即可立即永久解锁本站全部文章