使用Mockito的Java Optional.ofNullable

3

java.util中的Optional.ofNullable与Mockito一起使用是否正常运行?

在代码执行过程中,我遇到了这样的情况:

User user = Optional.ofNullable(userProviderMock.findUser()).orElse(someMethod())

我设置了以下的模拟行为:

我设定了以下的模拟行为:

when(userProviderMock.findUser()).thenReturn(new User());

当我运行程序时,userProviderMock返回了new User()(调试确认),但是一些奇怪的原因导致someMethod()仍然被执行。我真的不知道发生了什么,请问有任何线索吗?

我看不出Mockito在这里干扰的原因。你应该尝试找出Optional的实际值,例如在调用orElse之前检查其值,或者调试进入该方法。 - Jorn
当我在 Optional 上调用 isPresent() 方法时,结果为 true - krzakov
1个回答

8

Mockito 和 ofNullable 并不是问题的关键。考虑以下代码:

Optional.of("foo").orElse(someMethod())

上述代码将被评估为Optional.of("foo"),但它仍然要调用orElse,因此它仍然必须调用someMethod()以便将其返回值作为参数传递给orElse,即使该参数最终未被使用。
如果这对您来说是个问题——如果您不希望在实际需要其返回值之前调用someMethod(),那么您应该使用orElseGet
Optional.of("foo").orElseGet(() -> someMethod())

或者说:
User user = Optional.ofNullable(userProviderMock.findUser()).orElseGet(() -> someMethod())

编辑补充:Didier L 指出,() -> someMethod() 还可以写成 this::someMethod(也就是说可将其写为方法引用而不是lambda),这样可能更容易阅读。

无论哪种方式,它都会被隐式转换为大约如下代码:

User user = Optional.ofNullable(userProviderMock.findUser()).orElseGet(new Supplier<User>() {
    public User get() {
        return someMethod();
    }
});

someMethod()是复杂的公司逻辑,除非Optional为空,否则我不想调用它。 总之,orElse()orElseGet()的区别在于前者始终调用括号内的代码,无论是否使用,而后者仅在Optional为空时调用。对吗? - krzakov
3
嗯,并不完全如此。 Optional 没有任何特殊之处,它只是一个库类,没有能力规避执行 Java 代码的正常方式。特别地,orElse() 不会 "调用" 任何代码; 它的参数在 orElse 被调用 之前 被评估,就像在 Java 中始终发生的那样。区别在于 orElseGet() 不是取一个值来当 Optional 为空时使用,而是取一个供应商(Supplier) 在 Optional 为空时可以调用以获取要使用的值。因此,它仅在必要时才调用该供应商。这讲得通吗? - ruakh
4
你也可以写成 orElseGet(this::someMethod) 以避免使用lambda表达式。 - Didier L

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接