Kam Kam - 2 months ago 9
Java Question

Why is orGet part of Optional always runs?

class Ideone
{
public static String test() {
System.out.println("What is this?");
return "Hello";
}

public static void main (String[] args) throws java.lang.Exception
{
String result = Optional.ofNullable(new String()).map(c->c.toString()).orElse(Ideone.test());
System.out.println(result);
}
}


I expect that
test
function to never be called. But it is!

output is:
What is this?


result
was never set to
"Hello"
which is normal, but nevertheless
test
was called.

Also, when I use
orElseGet
instead, the
test
will never be called.

Shouldn't the
orElse
be called only when the
orElse
is needed? The point is if test() is not immutable, then I would've inadvertently mutated by class.

Answer

Your argument to orElse is just a plain String — in this case, one that you got by invoking a plain ol' method, Ideone.test(). Conceptually, it's no different from something like:

Collections.singleton(Ideaone.test());

First the inner expression is evaluated, and then that value becomes the argument for the outer expression.

If you want to defer the method call until you need it, use orElseGet instead, passing it a method reference:

... .orElseGet(Ideone::test);

or, if you prefer:

... .orElseGet( () -> Ideaone.test() );

In English terms, your original code said "... or else, get this String, which I'm providing right now by invoking this function." The method reference version says, "or else, call this method to get a String, and then use that String."

Comments