28

So after some reading I've seen that

if (optional.isPresent()) {
    //do smth
}

is not the preferred way to use Optional (http://www.oracle.com/technetwork/articles/java/java8-optional-2175753.html). But if I have an if-statement like this:

if (optional.isPresent()) {
    car = getCar(optional.get());
} else {
    car = new Car();
    car.setName(carName);
}

Is this the best way to do this or is there a more recommended way?

5
  • I doubt you even need the if statements, it kind of defies the whole point. Commented Jan 20, 2016 at 14:06
  • @assylias How does that work? The return of the optional would be an id and not a Car object? Commented Jan 20, 2016 at 14:14
  • 1
    Actually it is wrapper introduced to indicate to the developer that there can be an absense of returned value from some methods and he should take extra consideration. Commented Jan 20, 2016 at 14:16
  • @uraza I misread your code - apologies. Commented Jan 20, 2016 at 14:16
  • what's the logic on java not including this ability with OptionalXXX like OptionalDouble? Commented Aug 22, 2017 at 12:13

5 Answers 5

55

You can use Optional as following.

Car car = optional.map(id -> getCar(id))
            .orElseGet(() -> {
                Car c = new Car();
                c.setName(carName);
                return c;
            });

Writing with if-else statement is imperative style and it requires the variable car to be declared before if-else block.

Using map in Optional is more functional style. And this approach doesn't need variable declaration beforehand and is recommended way of using Optional.

Sign up to request clarification or add additional context in comments.

1 Comment

This does indeed seem to work. However, I do wonder if that makes the code any more readable or if there is any advantage in writing it this way.
9

If you can incorporate the name into the Car constructor, then you can write this:

car = optional.map(id -> getCar(id))
              .orElseGet(() -> new Car(carName));

If you must call the setter separately from your constructor, you would end up with something like this:

car = optional.map(id -> getCar(id))
              .orElseGet(() -> {
                  Car c = new Car();
                  c.setName(carName);
                  return c;
              });

4 Comments

Does orElseGet really return a Car object if the Optional is not empty?
If Car has a constructor with parameter carName, car = optional.orElse(new Car(carName)); could be used.
it looks like, the Op is using getCar method to get car rather than just from Optional.
Consider using the builder pattern
4

To take it further, if you have multiple if (optional.isPresent()) or if (obj != null)

You can do this:

(getN returns Optional<Car>)

return get1().map(Optional::of)
.orElseGet(() -> get2()).map(Optional::of)
.orElseGet(() -> get3()).map(Optional::of);

I.e. would be like this using if statements

Optional<Car> car = get1();
if (car.isPresent()){
  return car;
}
car = get2();
if (car.isPresent()){
  return car;
}
car = get3();
if (car.isPresent()){
  return car;
}
return Optional.empty();

2 Comments

Just note that if getN() can return a null value, you have to wrap it in Optional.ofNullable and that can become quite heavy to read : return Optional.ofNullable(get1()).map(Optional::of) .orElseGet(() -> Optional.ofNullable(get2())).map(Optional::of) .orElseGet(() -> Optional.ofNullable(get3())).map(Optional::of);
Java 9 now has Optional#or which hides the orElseGet and map(Optional::of) logic
0
Car car = optional.ifPresentOrElse(
id -> getCar(id),
() -> {
    Car c = new Car();
    c.setName(carName);
    return c;
};

);

This doesn't seem to work since ifPresentOrElse is void method, it won't return anything

2 Comments

As the OP who posted the comment said that this seem to work, if you have any supporting reason why this will not work and what will work, please add in your answer.
Tysvm for adding this answer. I happened to need this in a testing context. While I had noticed the .ifPresent() method, I had missed this perfect imperative solution of .ifPresentOrElse().
0

Optional API update. You can use or() method if you want to return return an Optional describing the value, otherwise returns an Optional produced by the supplying function.

For instance

private <T> Optional<T> getSetting(Integer Id, String country) {
    return repo.findByIdAndCountry(id, country,)
         .or(() -> repo.findDefaultByCountry(country))
         .or(() -> repo.findGlobalDefault());
}

The or() method description

/**
 * If a value is present, returns an {@code Optional} describing the value,
 * otherwise returns an {@code Optional} produced by the supplying function.
 *
 * @param supplier the supplying function that produces an {@code Optional}
 *        to be returned
 * @return returns an {@code Optional} describing the value of this
 *         {@code Optional}, if a value is present, otherwise an
 *         {@code Optional} produced by the supplying function.
 * @throws NullPointerException if the supplying function is {@code null} or
 *         produces a {@code null} result
 * @since 9
 */
public Optional<T> or(Supplier<? extends Optional<? extends T>> supplier) {
    Objects.requireNonNull(supplier);
    if (isPresent()) {
        return this;
    } else {
        @SuppressWarnings("unchecked")
        Optional<T> r = (Optional<T>) supplier.get();
        return Objects.requireNonNull(r);
    }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.