How to execute logic on Optional if not present?

JavaJava 8Optional

Java Problem Overview


I want to replace the following code using java8 Optional:

public Obj getObjectFromDB() {
	Obj obj = dao.find();
	if (obj != null) {
		obj.setAvailable(true);
	} else {
		logger.fatal("Object not available");
	}

	return obj;
}

The following pseudocode does not work as there is no orElseRun method, but anyways it illustrates my purpose:

public Optional<Obj> getObjectFromDB() {
	Optional<Obj> obj = dao.find();
	return obj.ifPresent(obj.setAvailable(true)).orElseRun(logger.fatal("Object not available"));
}

Java Solutions


Solution 1 - Java

With Java 9 or higher, ifPresentOrElse is most likely what you want:

Optional<> opt = dao.find();

opt.ifPresentOrElse(obj -> obj.setAvailable(true),
                    () -> logger.error("…"));

Currying using vavr or alike might get even neater code, but I haven't tried yet.

Solution 2 - Java

I don't think you can do it in a single statement. Better do:

if (!obj.isPresent()) {
    logger.fatal(...);   
} else {
    obj.get().setAvailable(true);
}
return obj;

Solution 3 - Java

For Java 8 Spring offers ifPresentOrElse from "Utility methods to work with Optionals" to achieve what you want. Example would be:

import static org.springframework.data.util.Optionals.ifPresentOrElse;    

ifPresentOrElse(dao.find(), obj -> obj.setAvailable(true), () -> logger.fatal("Object not available"));

Solution 4 - Java

You will have to split this into multiple statements. Here is one way to do that:

if (!obj.isPresent()) {
  logger.fatal("Object not available");
}

obj.ifPresent(o -> o.setAvailable(true));
return obj;

Another way (possibly over-engineered) is to use map:

if (!obj.isPresent()) {
  logger.fatal("Object not available");
}

return obj.map(o -> {o.setAvailable(true); return o;});

If obj.setAvailable conveniently returns obj, then you can simply the second example to:

if (!obj.isPresent()) {
  logger.fatal("Object not available");
}

return obj.map(o -> o.setAvailable(true));

Solution 5 - Java

There is an .orElseRun method, but it is called .orElseGet.

The main problem with your pseudocode is that .isPresent doesn't return an Optional<>. But .map returns an Optional<> which has the orElseGet method.

If you really want to do this in one statement this is possible:

public Optional<Obj> getObjectFromDB() {
    return dao.find()
        .map( obj -> { 
            obj.setAvailable(true);
            return Optional.of(obj); 
         })
        .orElseGet( () -> {
            logger.fatal("Object not available"); 
            return Optional.empty();
    });
}

But this is even clunkier than what you had before.

Solution 6 - Java

First of all, your dao.find() should either return an Optional<Obj> or you will have to create one.

e.g.

Optional<Obj> = dao.find();

or you can do it yourself like:

Optional<Obj> = Optional.ofNullable(dao.find());

this one will return Optional<Obj> if present or Optional.empty() if not present.

So now let's get to the solution,

public Obj getObjectFromDB() {
   return Optional.ofNullable(dao.find()).flatMap(ob -> {
            ob.setAvailable(true);
            return Optional.of(ob);    
        }).orElseGet(() -> {
            logger.fatal("Object not available");
            return null;
        });
    }

This is the one liner you're looking for :)

Solution 7 - Java

For those of you who want to execute a side-effect only if an optional is absent

i.e. an equivalent of ifAbsent() or ifNotPresent() here is a slight modification to the great answers already provided.

myOptional.ifPresentOrElse(x -> {}, () -> {
  // logic goes here
})

Solution 8 - Java

Title: "How to execute logic on Optional if not present?"
Answer:

Use orElseGet() as a workaround for the missing ifNotPresent(). And since it expects us to return something just return null.

Optional.empty().orElseGet(() -> {
    System.out.println("The object is not present");
    return null;
});

//output: The object is not present

or


Optional.ofNullable(null).orElseGet(() -> {
    System.out.println("The object is not present");
    return null;
});

//output: The object is not present

I also use it to easily implement the singleton pattern with lazy initialization.

public class Settings {
    private Settings(){}    
    private static Settings instance;
    public static synchronized Settings getInstance(){
        Optional.ofNullable(instance).orElseGet(() -> instance = new Settings());
        return instance;
    } 
}

Of course the getInstance() content can be written in one line by directly returning the first statement, but I wanted to demonstrate the use of orElseGet() as an ifNotPresent().

Solution 9 - Java

I was able to came up with a couple of "one line" solutions, for example:

    obj.map(o -> (Runnable) () -> o.setAvailable(true))
       .orElse(() -> logger.fatal("Object not available"))
       .run();

or

    obj.map(o -> (Consumer<Object>) c -> o.setAvailable(true))
       .orElse(o -> logger.fatal("Object not available"))
       .accept(null);

or

    obj.map(o -> (Supplier<Object>) () -> {
            o.setAvailable(true);
            return null;
    }).orElse(() () -> {
            logger.fatal("Object not available")
            return null;
    }).get();

It doesn't look very nice, something like orElseRun would be much better, but I think that option with Runnable is acceptable if you really want one line solution.

Solution 10 - Java

With Java 8 Optional it can be done with:

    Optional<Obj> obj = dao.find();

    obj.map(obj.setAvailable(true)).orElseGet(() -> {
        logger.fatal("Object not available");
        return null;
    });

Solution 11 - Java

You need Optional.isPresent() and orElse(). Your snippet won;t work because it doesn't return anything if not present.

The point of Optional is to return it from the method.

Solution 12 - Java

ifPresentOrElse can handle cases of nullpointers as well. Easy approach.

   Optional.ofNullable(null)
            .ifPresentOrElse(name -> System.out.println("my name is "+ name),
                    ()->System.out.println("no name or was a null pointer"));

Solution 13 - Java

I suppose you cannot change the dao.find() method to return an instance of Optional<Obj>, so you have to create the appropriate one yourself.

The following code should help you out. I've create the class OptionalAction, which provides the if-else mechanism for you.

public class OptionalTest
{
  public static Optional<DbObject> getObjectFromDb()
  {
    // doa.find()
    DbObject v = find();

    // create appropriate Optional
    Optional<DbObject> object = Optional.ofNullable(v);

    // @formatter:off
    OptionalAction.
    ifPresent(object)
    .then(o -> o.setAvailable(true))
    .elseDo(o -> System.out.println("Fatal! Object not available!"));
    // @formatter:on
    return object;
  }

  public static void main(String[] args)
  {
    Optional<DbObject> object = getObjectFromDb();
    if (object.isPresent())
      System.out.println(object.get());
    else
      System.out.println("There is no object!");
  }

  // find may return null
  public static DbObject find()
  {
    return (Math.random() > 0.5) ? null : new DbObject();
  }

  static class DbObject
  {
    private boolean available = false;

    public boolean isAvailable()
    {
      return available;
    }

    public void setAvailable(boolean available)
    {
      this.available = available;
    }

    @Override
    public String toString()
    {
      return "DbObject [available=" + available + "]";
    }
  }

  static class OptionalAction
  {
    public static <T> IfAction<T> ifPresent(Optional<T> optional)
    {
      return new IfAction<>(optional);
    }

    private static class IfAction<T>
    {
      private final Optional<T> optional;

      public IfAction(Optional<T> optional)
      {
        this.optional = optional;
      }

      public ElseAction<T> then(Consumer<? super T> consumer)
      {
        if (optional.isPresent())
          consumer.accept(optional.get());
        return new ElseAction<>(optional);
      }
    }

    private static class ElseAction<T>
    {
      private final Optional<T> optional;

      public ElseAction(Optional<T> optional)
      {
        this.optional = optional;
      }

      public void elseDo(Consumer<? super T> consumer)
      {
        if (!optional.isPresent())
          consumer.accept(null);
      }
    }
  }
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionmembersoundView Question on Stackoverflow
Solution 1 - JavaAndreasView Answer on Stackoverflow
Solution 2 - JavaKonstantin YovkovView Answer on Stackoverflow
Solution 3 - JavaCmykerView Answer on Stackoverflow
Solution 4 - JavaDuncan JonesView Answer on Stackoverflow
Solution 5 - JavaUTF_or_DeathView Answer on Stackoverflow
Solution 6 - JavaHasasnView Answer on Stackoverflow
Solution 7 - JavaStephen PaulView Answer on Stackoverflow
Solution 8 - JavaMarinos AnView Answer on Stackoverflow
Solution 9 - JavaerkfelView Answer on Stackoverflow
Solution 10 - JavasergeidygaView Answer on Stackoverflow
Solution 11 - JavaNimChimpskyView Answer on Stackoverflow
Solution 12 - JavaMuriithi DerrickView Answer on Stackoverflow
Solution 13 - JavamikeView Answer on Stackoverflow