DEV Community

Cover image for Be careful Of This Java Optional Method
Abdulcelil Cercenazi
Abdulcelil Cercenazi

Posted on • Edited on

Be careful Of This Java Optional Method

Let's Remember Java Optional 🤓

According to Oracle it's "A container object which may or may not contain a non-null value."
Optional was introduced in Java 8 and has been used by the SpringBoot team in many projects.


The most common usage of Optionals is in the Spring Data project. Let's look at the JpaRepository interface and an example method.
Say we have a User entity with an Id type of integer and that we have a JpaRepository for it

@Repository  
public interface IUserRepo extends JpaRepository<User, Integer>  
{  
    Optional<User> findByUserName(String userName);  
}
Enter fullscreen mode Exit fullscreen mode

We defined a method that searches for a user via their user name and returns an Optional of a User.


Optional's Convenience Methods 🙌

Optional comes in with many method meant to enable us to write clean and readable code.

  • map(..).or(...)
  • map(...).orElse(...)
  • check out Oracle's docs for the full list.

However, there is one method with a dangerously unexpected behavior


Meet The orElse Method 👀

According to Oracle's doc:

public T orElse(T other) 

Return the value if present, otherwise return other.

Now, we can add a method call as the parameter of the orElse, which will be run if the Optional is empty, right?

Yes, that's correct, BUT, what if I tell you that it will run anyways regardless of the presence of the value in Optional or not.


Let's test it ✍️

@Test  
public void orElseTest()  
{  
    String result = Optional.of("hello").orElse(someMethod());  
    assertThat(result).isEqualTo("hello");  
}  
private String someMethod()  
{  
    System.out.println("I am running !!");  
    return "hola";  
}
Enter fullscreen mode Exit fullscreen mode

The test does pass, but we notice that on the console we have the string "I am running" printed out.


Why is that? 🤨

  • Java runs the method to provide a value to be returned in the Else case.

So Be Careful ⛔️

We want to be careful if the method inside the orElse might have a side effect, because it will be run anyways.


What To Do then?

You can use the OrElseGet method which takes a supplier method to be executed if the Optional exists

Check out this wonderful comment for more details.


👉🏾 Also check out How to escape NullPointerExceptions in Java using Optional

Top comments (6)

Collapse
 
alexismanin profile image
Alexis Manin

Good article, with simple but good example.

However, I think there's some room for improvement. Mostly, The "Why is that" section looks like a bad reason for me. You could make a lot more value of your post if you take the time to properly explain what happens.

The method "orElse" does not take a function or lambda as argument, it takes a value. There's no JVM performance reason here. To give the value as argument of orElse, the method that produces it must be called "on-site".

It is a basic language understanding, and it is the same for any function in java.

To add emphasis why it is independent of performances :
JVM cannot really know how much it costs to call your method, and let you, the developper, choose if it should be called:

  • eagerly using orElse(Object) to provide a default value when assembling your Optional object, when it is created.

  • lazily, using orElseGet(Supplier) to provide a function that will compute a default value when the matching part of the optional is executed.

I think it would be far better to give users a proper understanding of this kind of difference (assembly vs execution, on-site vs defered execution). You could also give potential improvement solutions (like really caching default value yourself, to be sure the default value is computed a minimum amount of time).

Collapse
 
jarjanazy profile image
Abdulcelil Cercenazi

Yes you are right, I might have gone about explaining it the wrong way :D thanks for the feedback.
I will adjust the post accordingly

Collapse
 
scottshipp profile image
scottshipp

Another one to watch for: Optional.of. It's easy to assume that the behavior of this method when passed null will be to return an empty Optional. Instead, it throws a NullPointerException.

The more verbose Optional.ofNullable is the one that returns an empty Optional when passed null.

Collapse
 
blackr1234 profile image
blackr1234 • Edited

Great article for reminding Java developers! If the argument is a function call, it is better to use orElseGet instead.

Collapse
 
totally_chase profile image
Phantz

Buddy you're calling the function right there. Of course it is executed.

Collapse
 
jarjanazy profile image
Abdulcelil Cercenazi

Yes :D I've done this mistake many times though I thought I'd write about it