0

I've encountered an unexpected behavior while using the Optional API in Java.

Session session = sessionService
                            .getSessionById(id)
                            .orElse(
                                    sessionService.createSession(
                                            new Session(...)
                                    )
                            );

The above code executes the getSessionById() method returns the found object but then it also executes what's inside the orElse() method which shouldn't be possible since the object is present.

Why would the method inside orElse() get called before evaluating the presence of the Optional object first?

2
  • 9
    orElse() takes a value to return instead. In order to hand that value to the method, you need to compute it. That means in order to call orElse, the Session object must already exist. To avoid this, pass use orElseGet with a Supplier<Session> (trivial conversion: orElseGet( () => sessionService.createSession(...) ). Commented May 16 at 12:14
  • 4
    @JoachimSauer Small correction: Java lambda syntax uses a single dash in the arrow: () -> sessionService.creationSession(...)
    – Izruo
    Commented May 16 at 12:16

1 Answer 1

8

Because you’re executing sessionService.createSession before orElse is ever called.

Your code is exactly the same as writing this:

Session defaultSession = sessionService.createSession(new Session(...));
Session session = sessionService.getSessionById(id).orElse(defaultSession);

As you can see, the first line is called every single time.

A Supplier<Session> is different: creating a Supplier does not execute the Supplier’s get method. A Supplier is just a lightweight object whose get method may be executed at a later time, if other code chooses to do so.

8
  • "Because you’re executing sessionService.createSession before orElse is ever called." Are you sure about that? I have created an example where I assign the Optional to op. All that is left is to do is op.orElse(compute()); where compute is a static method that prints something and returns a value. If I branch around that statement, nothing gets printed which means compute was not called. So when does the compute() method actually get called? It seems to me that orElse triggers it.
    – WJS
    Commented May 16 at 13:37
  • @WJS how can it possibly be the orElse that "triggers" the call to compute()? The compiler doesn't know if the optional would be present or empty when it compiles the call to compute() and it has to call compute() in order to pass its result as an argument to orElse.
    – k314159
    Commented May 16 at 13:49
  • @k314159 If I don't execute op.orElse(compute()) I get no printing of a message. Perhaps my example is flawed. I am just trying to determine when the method is called. Perhaps it is called when op is simply accessed prior to invoking orElse.
    – WJS
    Commented May 16 at 13:53
  • 1
    @WJS 15.12.4. Run-Time Evaluation of Method Invocation - I think this is what you are looking for. The evaluation of argument expressions is the 2nd step, before method invokation.
    – Chaosfire
    Commented May 16 at 14:42
  • 1
    Formally, the createSession(...) is called between getSessionById(id) and the orElse(...), but it will be called unconditionally. Commented May 16 at 15:19

Not the answer you're looking for? Browse other questions tagged or ask your own question.