RichardK
RichardK

Reputation: 3471

Java 8 optional: ifPresent return object orElseThrow exception

I'm trying to make something like this:

 private String getStringIfObjectIsPresent(Optional<Object> object){
        object.ifPresent(() ->{
            String result = "result";
            //some logic with result and return it
            return result;
        }).orElseThrow(MyCustomException::new);
    }

This won't work, because ifPresent takes Consumer functional interface as parameter, which has void accept(T t). It cannot return any value. Is there any other way to do it ?

Upvotes: 94

Views: 250237

Answers (6)

Anderson
Anderson

Reputation: 2752

Since Java 9, we have ifPresentOrElse(). Unfortunately, the 2nd param is Runnable instead of exceptionSupplier.

We can add a helper method to make it pretty.

    public <X extends Throwable> Runnable toThrow(Supplier<X> exceptionSupplier) {
        return new Runnable() {

            @SneakyThrows
            @Override
            public void run() {
                throw exceptionSupplier.get();
            }

        };

    }

    // Pretty now
    opt.ifPresentOrElse(obj::setter, toThrow(IllegalStateException::new));

Upvotes: 1

Ryan Zheng
Ryan Zheng

Reputation: 73

The example u put is not a good example. Optional shouldn't be sent as parameter into another function. Good practice is always sending non-null parameter into function. So that we know always that the input will not be null. This can decrease our code uncertainty.

Upvotes: 1

Roland
Roland

Reputation: 23252

Actually what you are searching is: Optional.map. Your code would then look like:

object.map(o -> "result" /* or your function */)
      .orElseThrow(MyCustomException::new);

I would rather omit passing the Optional if you can. In the end you gain nothing using an Optional here. A slightly other variant:

public String getString(Object yourObject) {
  if (Objects.isNull(yourObject)) { // or use requireNonNull instead if NullPointerException suffices
     throw new MyCustomException();
  }
  String result = ...
  // your string mapping function
  return result;
}

If you already have the Optional-object due to another call, I would still recommend you to use the map-method, instead of isPresent, etc. for the single reason, that I find it more readable (clearly a subjective decision ;-)).

Upvotes: 108

iamiddy
iamiddy

Reputation: 3073

I'd prefer mapping after making sure the value is available

private String getStringIfObjectIsPresent(Optional<Object> object) {
   Object ob = object.orElseThrow(MyCustomException::new);
    // do your mapping with ob
   String result = your-map-function(ob);
  return result;
}

or one liner

private String getStringIfObjectIsPresent(Optional<Object> object) {
   return your-map-function(object.orElseThrow(MyCustomException::new));
}

Upvotes: 18

Vlad Bochenin
Vlad Bochenin

Reputation: 3072

Two options here:

Replace ifPresent with map and use Function instead of Consumer

private String getStringIfObjectIsPresent(Optional<Object> object) {
    return object
            .map(obj -> {
                String result = "result";
                //some logic with result and return it
                return result;
            })
            .orElseThrow(MyCustomException::new);
}

Use isPresent:

private String getStringIfObjectIsPresent(Optional<Object> object) {
    if (object.isPresent()) {
        String result = "result";
        //some logic with result and return it
        return result;
    } else {
        throw new MyCustomException();
    }
}

Upvotes: 33

marstran
marstran

Reputation: 28016

Use the map-function instead. It transforms the value inside the optional.

Like this:

private String getStringIfObjectIsPresent(Optional<Object> object) {
    return object.map(() -> {
        String result = "result";
        //some logic with result and return it
        return result;
    }).orElseThrow(MyCustomException::new);
}

Upvotes: 18

Related Questions