314

I am trying to understand the difference between the Optional<T>.orElse() and Optional<T>.orElseGet() methods.

The description for the orElse() method is:

Return the value if present, otherwise return other.

While, the description for the orElseGet() method is:

Return the value if present, otherwise invoke other and return the result of that invocation.

The orElseGet() method takes a Supplier functional interface, which essentially does not take any parameters and returns T.

In which situation would you need to use orElseGet()? If you have a method T myDefault() why wouldn't you just do optional.orElse(myDefault()) rather than optional.orElseGet(() -> myDefault()) ?

It does not seem that orElseGet() is postponing the execution of the lambda expression to some later time or something, so what's the point of it? (I would have thought that it would be more useful if it returned a safer Optional<T> whose get() never throws a NoSuchElementException and isPresent() always returns true... but evidently its not, it just returns T like orElse()).

Is there some other difference I am missing?

4
  • 10
    The reason is when you use orElseGet it calls supplier only if value is absent. Commented Oct 16, 2015 at 12:09
  • 16
    Ah ok got it. So in the case of orElse() the myDefault() method is still called, but its return value is just not used.
    – jbx
    Commented Oct 16, 2015 at 12:16
  • 4
    Upvoted question because from what I've seen misunderstanding or simply forgetting to use orElseGet() can result in some serious bugs: medium.com/alphadev-thoughts/…
    – softarn
    Commented May 24, 2018 at 15:07
  • 2
    A good explanation is found here: baeldung.com/java-optional-or-else-vs-or-else-get Commented Jun 9, 2020 at 14:29

10 Answers 10

271
+200

Short Answer:

  • orElse() will always call the given function whether you want it or not, regardless of Optional.isPresent() value
  • orElseGet() will only call the given function when the Optional.isPresent() == false

In real code, you might want to consider the second approach when the required resource is expensive to get.

// Always get heavy resource
getResource(resourceId).orElse(getHeavyResource()); 

// Get heavy resource when required.
getResource(resourceId).orElseGet(() -> getHeavyResource()) 

For more details, consider the following example with this function:

public Optional<String> findMyPhone(int phoneId)

The difference is as below:

                           X : buyNewExpensivePhone() called

+——————————————————————————————————————————————————————————————————+——————————————+
|           Optional.isPresent()                                   | true | false |
+——————————————————————————————————————————————————————————————————+——————————————+
| findMyPhone(int phoneId).orElse(buyNewExpensivePhone())          |   X  |   X   |
+——————————————————————————————————————————————————————————————————+——————————————+
| findMyPhone(int phoneId).orElseGet(() -> buyNewExpensivePhone()) |      |   X   |
+——————————————————————————————————————————————————————————————————+——————————————+

When optional.isPresent() == false, there is no difference between two ways. However, when optional.isPresent() == true, orElse() always calls the subsequent function whether you want it or not.

Finally, the test case used is as below:

Result:

------------- Scenario 1 - orElse() --------------------
  1.1. Optional.isPresent() == true (Redundant call)
    Going to a very far store to buy a new expensive phone
    Used phone: MyCheapPhone

  1.2. Optional.isPresent() == false
    Going to a very far store to buy a new expensive phone
    Used phone: NewExpensivePhone

------------- Scenario 2 - orElseGet() --------------------
  2.1. Optional.isPresent() == true
    Used phone: MyCheapPhone

  2.2. Optional.isPresent() == false
    Going to a very far store to buy a new expensive phone
    Used phone: NewExpensivePhone

Code:

public class TestOptional {
    public Optional<String> findMyPhone(int phoneId) {
        return phoneId == 10
                ? Optional.of("MyCheapPhone")
                : Optional.empty();
    }

    public String buyNewExpensivePhone() {
        System.out.println("\tGoing to a very far store to buy a new expensive phone");
        return "NewExpensivePhone";
    }


    public static void main(String[] args) {
        TestOptional test = new TestOptional();
        String phone;
        System.out.println("------------- Scenario 1 - orElse() --------------------");
        System.out.println("  1.1. Optional.isPresent() == true (Redundant call)");
        phone = test.findMyPhone(10).orElse(test.buyNewExpensivePhone());
        System.out.println("\tUsed phone: " + phone + "\n");

        System.out.println("  1.2. Optional.isPresent() == false");
        phone = test.findMyPhone(-1).orElse(test.buyNewExpensivePhone());
        System.out.println("\tUsed phone: " + phone + "\n");

        System.out.println("------------- Scenario 2 - orElseGet() --------------------");
        System.out.println("  2.1. Optional.isPresent() == true");
        // Can be written as test::buyNewExpensivePhone
        phone = test.findMyPhone(10).orElseGet(() -> test.buyNewExpensivePhone());
        System.out.println("\tUsed phone: " + phone + "\n");

        System.out.println("  2.2. Optional.isPresent() == false");
        phone = test.findMyPhone(-1).orElseGet(() -> test.buyNewExpensivePhone());
        System.out.println("\tUsed phone: " + phone + "\n");
    }
}
8
  • 1
    I think you may have an Error in your picture, it should say "orElseGet" on the right ? Besides that, great example.
    – Yalla T.
    Commented Feb 2, 2018 at 11:56
  • Yes you are correct. Thank you :) I will update it in next few hours
    – Hoa Nguyen
    Commented Feb 2, 2018 at 12:35
  • For the second bullet point, seems should be Optional.isPresent() == false instead (false, not true) Commented May 31, 2018 at 16:50
  • 2
    Great example - but I really don't get how the Javadocs for Optional.orElsewhich states If a value is present, returns the value, otherwise returns other can imply this behaviour... Commented Nov 23, 2018 at 12:44
  • 1
    @Mike - sure, but it's probably not a very good mnemonic to keep because they are also vastly different concepts. They just happen to be comparable in this specific instance but it's a bit like saying that cloud over there looks like a horse ;)
    – Oskar Lund
    Commented Mar 8, 2022 at 10:43
239

Take these two scenarios:

Optional<Foo> opt = ...
Foo x = opt.orElse( new Foo() );
Foo y = opt.orElseGet( Foo::new );

If opt doesn't contain a value, the two are indeed equivalent. But if opt does contain a value, how many Foo objects will be created?

P.s.: of course in this example the difference probably wouldn't be measurable, but if you have to obtain your default value from a remote web service for example, or from a database, it suddenly becomes very important.

13
  • 43
    Thanks for the clarification guys. So the difference is subtle but significant. In the second case, it won't create a new Foo object, while in the first case it will create it, but not use it if there is a value inside the Optional.
    – jbx
    Commented Oct 16, 2015 at 12:18
  • 8
    @jbx Yes, and in my noddy example it arguably doesn't make any real difference, but if you have to obtain your default value from a remote web service for example, or from a database, the difference suddenly becomes very important.
    – biziclop
    Commented Oct 16, 2015 at 12:19
  • 2
    @jbx: you are mixing two things up. There are already questions on SO regarding strange benchmark results which simply were cause by not using the result of a computation. The JVM can do that. On the other hand, System.out.println() is not a calculation but a statement producing an observable side-effect. And I already said that observable side-effects will hinder optimizations (the console output stream is an external resource).
    – Holger
    Commented Oct 16, 2015 at 14:06
  • 24
    That's the first time I see a question instead of an answer been accepted.
    – Kirill G.
    Commented Jan 26, 2018 at 5:07
  • 6
    "if you have to obtain your default value from a remote web service for example" this was my scenario exactly. In my case, the optional was a query, and the default in the absence of a query was to fetch all values...yeah, orElseGet reduced the runtime of that operation by 1000 times. Commented Aug 8, 2018 at 14:19
85

I reached here for the problem Kudo mentioned.

I'm sharing my experience for others.

orElse, or orElseGet, that is the question:

static String B() {
    System.out.println("B()...");
    return "B";
}

public static void main(final String... args) {

    System.out.println(
        Optional.of("A").orElse(B()) // B()'s gonna be invoked anyway
    );

    System.out.println("----");

    System.out.println(
        Optional.of("A").orElseGet(() -> B()) // B() won't be invoked
    );
}

prints

B()...
A
----
A

orElse evaluates the value of B() independently of the value of the optional. Thus, orElseGet is lazy.

3
  • 8
    It is not a 'problem'. It is the simple fact that the argument for a method is evaluated prior to the method execution. If you pass B() to a method named orElse() or abc() it does not make any difference, B() gets evaluated.
    – jbx
    Commented Jan 14, 2017 at 11:37
  • 25
    The issue here is really the naming of the methods. The or prefix misleads developers (including myself when I asked the problem) into thinking that it is a short-circuiting operation, because that is what we are used to in boolean conditions. However, it is not, it is just a method name that has or in its prefix, so its arguments will be evaluated, irrespective of whether Optional is carrying a value or not. It is unfortunate that the naming is confusing, not that we can do anything about it.
    – jbx
    Commented Nov 19, 2017 at 21:15
  • 3
    Thanks for the answer. Must say the language designers did not think thru as to how confusing this could get.
    – Thyag
    Commented Jan 20, 2021 at 10:32
39

I would say the biggest difference between orElse and orElseGet comes when we want to evaluate something to get the new value in the else condition.

Consider this simple example -

// oldValue is String type field that can be NULL
String value;
if (oldValue != null) {
    value = oldValue;
} else {
    value = apicall().value;
}

Now let's transform the above example to using Optional along with orElse,

// oldValue is Optional type field
String value = oldValue.orElse(apicall().value);

Now let's transform the above example to using Optional along with orElseGet,

// oldValue is Optional type field
String value = oldValue.orElseGet(() -> apicall().value);

When orElse is invoked, the apicall().value is evaluated and passed to the method. Whereas, in the case of orElseGet the evaluation only happens if the oldValue is empty. orElseGet allows lazy evaluation.

1
  • 5
    I wasted a lot of times because of this "strange" behavior of ifElse(). I'd say it makes sense to prefer ifElseGet() over ifElse() Commented Jun 6, 2017 at 14:40
7

First of all check the declaration of both the methods.

1) OrElse: Execute logic and pass result as argument.

public T orElse(T other) {    
 return value != null ? value : other;
}

2) OrElseGet: Execute logic if value inside the optional is null

public T orElseGet(Supplier<? extends T> other) {
  return value != null ? value : other.get(); 
}

Some explanation on above declaration: The argument of “Optional.orElse” always gets executed irrespective of the value of the object in optional (null, empty or with value). Always consider the above-mentioned point in mind while using “Optional.orElse”, otherwise use of “Optional.orElse” can be very risky in the following situation.

Risk-1) Logging Issue: If content inside orElse contains any log statement: In this case, you will end up logging it every time.

Optional.of(getModel())
   .map(x -> {
      //some logic
   })
  .orElse(getDefaultAndLogError());
 
getDefaultAndLogError() {
  log.error("No Data found, Returning default");
  return defaultValue;
}

Risk-2) Performance Issue: If content inside orElse is time-intensive: Time intensive content can be any i/o operations DB call, API call, file reading. If we put such content in orElse(), the system will end up executing a code of no use.

Optional.of(getModel())
   .map(x -> //some logic)
   .orElse(getDefaultFromDb());

getDefaultFromDb() {
   return dataBaseServe.getDefaultValue(); //api call, db call.
}

Risk-3) Illegal State or Bug Issue: If content inside orElse is mutating some object state: We might be using the same object at another place let say inside Optional.map function and it can put us in a critical bug.

List<Model> list = new ArrayList<>();
Optional.of(getModel())
  .map(x -> {
  })
  .orElse(get(list));

get(List < String > list) {
   log.error("No Data found, Returning default");
   list.add(defaultValue);
   return defaultValue;
}

Then, When can we go with orElse()? Prefer using orElse when the default value is some constant object, enum. In all above cases we can go with Optional.orElseGet() (which only executes when Optional contains empty value)instead of Optional.orElse(). Why?? In orElse, we pass default result value, but in orElseGet we pass Supplier and method of Supplier only executes if the value in Optional is null.

Key takeaways from this:

  1. Do not use “Optional.orElse” if it contains any log statement.
  2. Do not use “Optional.orElse” if it contains time-intensive logic.
  3. Do not use “Optional.orElse” if it is mutating some object state.
  4. Use “Optional.orElse” if we have to return a constant, enum.
  5. Prefer “Optional.orElseGet” in the situations mentioned in 1,2 and 3rd points.

I have explained this in point-2 (“Optional.map/Optional.orElse” != “if/else”) my medium blog. Use Java8 as a programmer not as a coder

1
  • Excellent answer :) Commented Jun 17, 2021 at 10:58
5

The difference is pretty subtle and if you dont pay much attention then you will keep it using in a wrong way.

Best way to understand the difference between orElse() and orElseGet() is that orElse() will always be executed if the Optional<T> is null or not, But orElseGet() will only be executed when Optional<T> is null.

The dictionary meaning of orElse is :- execute the part when something is not present, but here it contradicts, see the below example:

    Optional<String> nonEmptyOptional = Optional.of("Vishwa Ratna");
    String value = nonEmptyOptional.orElse(iAmStillExecuted());

    public static String iAmStillExecuted(){
    System.out.println("nonEmptyOptional is not NULL,still I am being executed");
    return "I got executed";
    }

Output: nonEmptyOptional is not NULL,still I am being executed


    Optional<String> emptyOptional = Optional.ofNullable(null);
    String value = emptyOptional.orElse(iAmStillExecuted());
    public static String iAmStillExecuted(){
    System.out.println("emptyOptional is NULL, I am being executed, it is normal as 
    per dictionary");
    return "I got executed";
    }

Output: emptyOptional is NULL, I am being executed, it is normal as per dictionary

For orElseGet() , The method goes as per dictionary meaning, The orElseGet() part will be executed only when the Optional is null.

Benchmarks:

+--------------------+------+-----+------------+-------------+-------+
| Benchmark          | Mode | Cnt | Score      | Error       | Units |
+--------------------+------+-----+------------+-------------+-------+
| orElseBenchmark    | avgt | 20  | 60934.425  | ± 15115.599 | ns/op |
+--------------------+------+-----+------------+-------------+-------+
| orElseGetBenchmark | avgt | 20  | 3.798      | ± 0.030     | ns/op |
+--------------------+------+-----+------------+-------------+-------+

Remarks: orElseGet() has clearly outperformed orElse() for our particular example.

Hope it clears the doubts of people like me who wants the very basic ground example :)

3

The following example should demonstrate the difference:

String destroyTheWorld() {
  // destroy the world logic
  return "successfully destroyed the world";
}

Optional<String> opt = Optional.of("Save the world");

// we're dead
opt.orElse(destroyTheWorld());

// we're safe    
opt.orElseGet(() -> destroyTheWorld());

The answer appears in the docs as well.

public T orElseGet(Supplier<? extends T> other):

Return the value if present, otherwise invoke other and return the result of that invocation.

The Supplier won't be invoked if the Optional presents. whereas,

public T orElse(T other):

Return the value if present, otherwise return other.

If other is a method that returns a string, it will be invoked, but it's value won't be returned in case the Optional exists.

3
  • In the given example, 'we are dead' in both cases. Optional<String> opt = Optional.empty(); will return optional with value null. orElse logic inside value != null ? value : other. orElseGet logic inside value != null ? value : supplier.get(). In the given example, both invoke destroyTheWorld() Commented Jul 22, 2020 at 13:14
  • @ABHIJITHKINI In the second case, the method will not be actually executed. Don't worry, I saved the world.
    – Maroun
    Commented Jul 22, 2020 at 13:25
  • 1
    In the given example, It will; Please execute below : Optional<String> opt = Optional.empty(); opt.orElseGet(() -> destroyTheWorld()); in the console : successfully destroyed the world because opt value is NULL. Commented Jul 23, 2020 at 10:33
1

Considering the following code:

import java.util.Optional;

// one class needs to have a main() method
public class Test
{
  public String orelesMethod() {
    System.out.println("in the Method");
    return "hello";
  }

  public void test() {
    String value;
    value = Optional.<String>ofNullable("test").orElseGet(this::orelesMethod);
    System.out.println(value); 

    value = Optional.<String>ofNullable("test").orElse(orelesMethod());
    System.out.println(value); 
  }

  // arguments are passed using the text field below this editor
  public static void main(String[] args)
  {
    Test test = new Test();

    test.test();
  }
}

if we get value in this way: Optional.<String>ofNullable(null), there is no difference between orElseGet() and orElse(), but if we get value in this way: Optional.<String>ofNullable("test"), orelesMethod() in orElseGet() will not be called but in orElse() it will be called

1

They are both used to return a default value for one Optional, but if a method is used to produce the dafault value:

  • orElse: always executes the method, also if the Optional is not empty
  • orElseGet: executes it only if the Optional is empty (+ Performance!)

see this example (class OptionalExample):

public static void main(String[] args) {

    Optional<String> optionalNotEmpty = Optional.of("StringVal");
    
    // orElse: getDefaultValue called (useless)
    System.out.println(optionalNotEmpty.orElse(getDefaultValue()));
    
    // orElseGet: getDefaultValue not called (better solution)
    System.out.println(optionalNotEmpty.orElseGet(OptionalExample::getDefaultValue));
}

public static String getDefaultValue() {
    System.out.println("called");
    return "default value";
}

Output:

called
StringVal
StringVal
-1

Here is an example test for orElse which shows this rather unintuitive behavior of Optional.orElse which executes even if the first Optional value was present.

    @Test
    void testOptionalOrElseInvocation() {
        Runnable runnable = Mockito.mock(Runnable.class);
        Integer result = method1(runnable).orElse(method2(runnable).get());
        assertEquals(1, result);
        Mockito.verify(runnable, Mockito.times(1)).run();
    }

    private Optional<Integer> method1(Runnable runnable) {
        runnable.run();
        return Optional.of(1);
    }

    private Optional<Integer> method2(Runnable runnable) {
        runnable.run();
        return Optional.of(2);
    }

This test fails with

org.mockito.exceptions.verification.TooManyActualInvocations: 
runnable.run();
Wanted 1 time:
-> at com.mycompany.rasapi.service.OptionalTest.testOptionalOrElseInvocation(OptionalTest.java:10)
But was 2 times:

The method1 returned a value but it still went and executed method2.

1
  • 1
    Yes. The problem is with the naming being unintuitive. It is a method just like the others so it will always be executed. If it was named getWithDefault instead of orElse it would be more obvious that the default value is still computed, just not used if the Optional is not empty.
    – jbx
    Commented Sep 10, 2023 at 7:52

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