从 Java 返回可选 ifPresent()

Returning from Java Optional ifPresent()

我知道你不能从 ifPresent() return 所以这个例子不起作用:

public boolean checkSomethingIfPresent() {
    mightReturnAString().ifPresent((item) -> {
        if (item.equals("something")) {
            // Do some other stuff like use "something" in API calls
            return true; // Does not compile
        }
    });
    return false;
}

其中 mightReturnAString() 可以 return 有效字符串或空可选。我所做的工作是:

public boolean checkSomethingIsPresent() {
    Optional<String> result = mightReturnAString();

    if (result.isPresent()) {
        String item = result.get();
        if (item.equals("something") {
            // Do some other stuff like use "something" in API calls
            return true;
        }
    }
    return false;
}

它更长,并且与首先检查空值没有太大区别。我觉得一定有更简洁的方式使用 Optional.

如何映射到布尔值?

public boolean checkSomethingIfPresent() {
    return mightReturnAString().map(item -> {
        if (item.equals("something")) {
            // Do some other stuff like use "something" in API calls
            return true; // Does not compile
        }
        return false; // or null
    }).orElse(false);
}

我认为您要查找的只是 filter 然后检查是否存在:

return result.filter(a -> a.equals("something")).isPresent();

虽然@nullpointer 和@Ravindra 展示了如何将 Optional 与另一个条件合并,但您必须做更多的工作才能调用 API 并执行您在问题中提出的其他操作。在我看来,以下内容看起来非常可读和简洁:

private static boolean checkSomethingIfPresent() {
    Optional<String> str = mightReturnAString();
    if (str.filter(s -> s.equals("something")).isPresent()) {
        //call APIs here using str.get()
        return true;
    }
    return false;
}

更好的设计是链接方法:

private static void checkSomethingIfPresent() {
    mightReturnFilteredString().ifPresent(s -> {
        //call APIs here
    });
}

private static Optional<String> mightReturnFilteredString() {
    return mightReturnAString().filter(s -> s.equals("something"));
}

private static Optional<String> mightReturnAString() {
    return Optional.of("something");
}

理想的解决方案是“命令查询分离”:创建一个方法(命令)来处理字符串(如果存在)。还有另一种方法(查询)告诉你它是否在那里。

然而,我们并没有生活在一个理想的世界中,完美的解决方案是永远不可能的。如果在您的情况下您不能将命令和查询分开,我的口味是 shmosel 已经提出的想法:映射到 boolean。作为细节,我会使用 filter 而不是内部 if 语句:

public boolean checkSomethingIfPresent() {
    return mightReturnAString().filter(item -> item.equals("something"))
            .map(item -> {
                // Do some other stuff like use "something" in API calls
                return true; // (compiles)
            })
            .orElse(false);
}

我不喜欢它的是调用链有一个副作用,这通常不是预期的,除了 ifPresentifPresentOrElse(和 orElseThrow,当然)。

如果硬要用ifPresent让副作用更清楚,那是可以的:

    AtomicBoolean result = new AtomicBoolean(false);
    mightReturnAString().filter(item -> item.equals("something"))
            .ifPresent(item -> {
                // Do some other stuff like use "something" in API calls
                result.set(true);
            });
    return result.get();

我使用 AtomicBoolean 作为结果的容器,因为我们不允许从 lambda 中分配给原语 boolean。我们不需要它的原子性,但它也没有坏处。

Link: Command–query separation 维基百科

顺便说一下,如果你真的想从 Optional 中获取值,请使用:

Optional<User> user = service.getCurrentUset();

return user.map(User::getId);