java - Optional 的 `orElse` 惰性评估失败导致性能下降

标签 java option-type

考虑以下具有用户偏好系统的应用程序用例:

我们想要获取偏好 MyFlag 的 bool 值。
在最好的情况下,我们希望它来自当前用户的设置。
如果失败,我们希望从默认设置中获取 MyFlag
如果失败,则抛出。

设置在服务器上。此连接很慢,可能会失败。
获取设置和获取首选项也可能全部失败。
所以让我们使用 javas Optionals:

public static boolean getMyFlag()throws NoSuchElementException
{
        return getUserOrDefaultPreference("MY_FLAG");
}

private Boolean getUserOrDefaultPreference(String preferenceName) throws NoSuchElementException
{
    return Optional.ofNullable(getConnection())              // get slow connection
        .map(connection -> connection.getUserSettings())     // get user settings
        .map(settings -> settings.getPref(preferenceName))   // return preference
        .orElse(slowlyGetDefaultPreference(preferenceName)); // or else return default value
}

private Boolean slowlyGetDefaultPreference(String preferenceName) throws NoSuchElementException
{
    return Optional.ofNullable(getConnection())             // get slow connection
        .map(connection -> connection.getDefaultSettings()) // get default settings
        .map(settings -> settings.getPref(preferenceName))  // return preference
        .orElseThrow(() ->  new NoSuchElementException());  // if any of the above fails throw
}

这里的问题是连接速度可能非常慢。当 .orElse(slowlyGet...); 被调用时,函数 slowlyGetDefaultPreference() 首先被评估,不管我的可选是空的还是有一个值。这是一种性能损失,我必须避免。

我尝试通过 .orElseGet(() -> slowlytGet..) 使用供应商,但这导致了同样的问题。

所以我唯一的办法是丑陋的 isPresent() 反模式,从可读性的角度来看,它破坏了整个可选流程:

private Boolean getUserOrDefaultPreference(String preferenceName) throws NoSuchElementException
{
    Optional<Boolean> opt = Optional.ofNullable(getConnection())
        .map(connection -> connection.getUserSettings())  
        .map(settings -> settings.getPref(preferenceName));

    if(opt.isPresent())
    {
        return opt.get();
    }
    else
    {
        slowlyGetDefaultPreference(preferenceName));
    }
}

抛出异常也是如此,因为我不想支付构建异常的成本。

我是不是遗漏了什么,或者这是唯一的解决方案吗?

最佳答案

orElse()orElseGet(lambdas) 的区别是,第一个函数总是被调用,但是 orElseGet 被调用,当Optional.ofNullable()orElseGet 之前的某些对象为 null。

这意味着,如果你不想每次都从orElse()调用方法,你必须使用orElseGet()

在您的示例中,对于您的方法slowlyGetDefaultPreference(preferenceName),请使用orElseGet()

return Optional.ofNullable(getConnection())              // get slow connection
    .map(connection -> connection.getUserSettings())     // get user settings
    .map(settings -> settings.getPref(preferenceName))   // return preference
    .orElseGet(() -> slowlyGetDefaultPreference(preferenceName));

那么当 map 函数中的所有对象都不是 null

时,您的代码不会评估最后一个方法

关于java - Optional 的 `orElse` 惰性评估失败导致性能下降,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42108486/

相关文章:

java - 如何使用 PowerMock 测试从同一类调用另一个私有(private) void 方法的方法?

java - 在Java中生成以N的倍数递增的随机数

java - 如何使用正则表达式从字符串中解析数字

java - 独特的 Java 和 Javascript 交织行为

swift - 一起使用 let 和 if - Swift Guided Tour Playground

java - 嵌套逆变类型中的类型不匹配

swift - NSNumberFormatter.stringFromNumber 会返回 nil 吗?

C#方法第二个参数可选

ios - 从 CoreData 中解包 Date() 类型的选项?

swift - do - try - catch 代码不尝试或捕获。只是做