Java可选的评估副作用

Den*_*Ich 6 java lambda

我在评估Java选项时遇到了一些麻烦.考虑以下测试:

@Test
public void test() {
    System.out.println("GOT STRING: " + first().orElse(second()));
}

private Optional<String> first() {
    System.out.println("Evaluating first");
    return Optional.of("STRING OPTIONAL");
}

private String second() {
    System.out.println("Evaluating second");
    return "SECOND STRING";
}
Run Code Online (Sandbox Code Playgroud)

我的期望是,因为first()返回非空的Optional,所以不评估第二个.但事实上输出是:

Evaluating first
Evaluating second
GOT STRING: STRING OPTIONAL
Run Code Online (Sandbox Code Playgroud)

尝试在测试中使用orElse中使用的函数:

@Test
public void test2() {
    System.out.println("GOT STRING: " + (first() != null ? "FIRST IS NOT NULL" : second()));
}
Run Code Online (Sandbox Code Playgroud)

输出:

Evaluating first
GOT STRING: FIRST IS NOT NULL
Run Code Online (Sandbox Code Playgroud)

为什么评估第二个选项?这似乎很糟糕?

Art*_*ski 10

它被评估,因为你传递的是值的second()值,而不是仅仅传递对函数本身的引用.您需要执行以下操作之一

System.out.println("GOT STRING: " + first().orElseGet(() ->second()));
System.out.println("GOT STRING: " + first().orElseGet(this::second));
Run Code Online (Sandbox Code Playgroud)

延迟评估直到真正需要.


Jon*_*eet 7

为什么评估第二个选项?

因为您正在调用second()方法,以便将值作为参数提供orElse().参数的值将被忽略(因为您已经有了一个值),但这并不意味着它不必提供.

基本上,这段代码:

first().orElse(second())
Run Code Online (Sandbox Code Playgroud)

相当于:

Optional<String> tmp1 = first();
Optional<String> tmp2 = second();
Optional<String> result = tmp1.orElse(tmp2);
Run Code Online (Sandbox Code Playgroud)

这里没有任何特定的可选项 - 这就是参数评估在Java中始终有效的方式.

请注意,这是构造(orElse)和条件运算符语言 construct(?:)之间的一个很大区别,它只会计算第二个第三个操作数,但不会同时评估两者.

正如Artur所提到的,如果你想将调用推迟到second(),你需要使用orElseGet,你传递的参数不是要使用的值,如果first没有,那么调用make以获取值.

  • 我看了使用该语言构造的orElse的实现。因此,我应该表现出与之相当的行为。但您的解释适合这里。对我来说,这似乎仍然是错误的简单来源,应记录在案。虽然您对评估的看法是正确的。我有点忘了使用该功能。 (2认同)