373

In Java 8, I want to do something to an Optional object if it is present, and do another thing if it is not present.

if (opt.isPresent()) {
  System.out.println("found");
} else {
  System.out.println("Not found");
}

This is not a 'functional style', though.

Optional has an ifPresent() method, but I am unable to chain an orElse() method.

Thus, I cannot write:

opt.ifPresent( x -> System.out.println("found " + x))
   .orElse( System.out.println("NOT FOUND"));

In reply to @assylias, I don't think Optional.map() works for the following case:

opt.map( o -> {
  System.out.println("while opt is present...");
  o.setProperty(xxx);
  dao.update(o);
  return null;
}).orElseGet( () -> {
  System.out.println("create new obj");
  dao.save(new obj);
  return null;
});

In this case, when opt is present, I update its property and save to the database. When it is not available, I create a new obj and save to the database.

Note in the two lambdas I have to return null.

But when opt is present, both lambdas will be executed. obj will be updated, and a new object will be saved to the database . This is because of the return null in the first lambda. And orElseGet() will continue to execute.

Nathaniel Ford
  • 20,545
  • 20
  • 91
  • 102
smallufo
  • 11,516
  • 20
  • 73
  • 111
  • [`orElse`](http://docs.oracle.com/javase/8/docs/api/java/util/Optional.html#orElse-T-) is meant for something different. – Sotirios Delimanolis May 21 '14 at 02:34
  • Yes , I know . I just want something like that. – smallufo May 21 '14 at 02:35
  • 84
    Use your first sample. It is _beautiful_. – Sotirios Delimanolis May 21 '14 at 02:37
  • 5
    I suggest you stop forcing certain behaviour when using an API that is not designed for that behaviour. You rfirst example looks fine to me apart from some small style remarks, but those are opiniated. – skiwi May 21 '14 at 06:55
  • 1
    `System.out.println( (opt.isPresent()? "" : "Not ") + "found");` – Marko Topolnik May 21 '14 at 08:21
  • 4
    @smallufo: replace `return null;` with `return o;` (both). However, I have the strong feeling that you are working at the wrong place. You should work at the site which produced that `Optional`. At that place there should be a way of performing the desired operation without the intermediate `Optional`. – Holger May 22 '14 at 16:41
  • 12
    Java 9 implements a solution for your problem: http://iteratrlearning.com/java9/2016/09/05/java9-optional.html – Pikachu Sep 15 '16 at 23:26
  • 2
    I think the reason this cannot be done easily is on purpose. Optional should not do flow control, but rather value transformation. I know the `ifPresent` contradicts this. All other methods refer to the value and not actions. – AlikElzin-kilaka Jul 20 '17 at 10:39
  • 1
    I would argue your second example, which uses `map`, is even less functional than the `ifPresent` version. In functional programming, functions must not produce any side effects such as printing and modifying other values. They can only do calculations. I avoid using `map` anytime I'm trying to produce side effects. When seeing `map` called, it's natural to assume that there won't be side effects, only a transformation of a value because of it's functional background. Using it in the way that the name suggests is a much more semantic way to program. – Addison Oct 15 '18 at 15:28
  • Also, I'm not sure about in Java, but in many languages such as Rust and Haskell, `map` is a lazy operation, meaning it won't actually call the block you pass until you try to use or check the value of the optional. So depending on the language, a statement like that may never be executed and as a result get optimized away. This may not apply to Java, but it's something important to be aware of. – Addison Oct 15 '18 at 15:41
  • 1
    Java loves to get you half way there and then cluster-up the rest. Obviously you should be able to chain `ifPresent(...)` with `orElse(...)` or `otherwise(...)`. – Josh M. Aug 14 '19 at 23:20
  • See also [Chaining Optionals in Java 8](https://stackoverflow.com/questions/28514704/chaining-optionals-in-java-8) – Vadzim Dec 09 '19 at 11:52

13 Answers13

308

If you are using Java 9+, you can use ifPresentOrElse() method:

opt.ifPresentOrElse(
   value -> System.out.println("Found: " + value),
   () -> System.out.println("Not found")
);
ZhekaKozlov
  • 36,558
  • 20
  • 126
  • 155
128

For me the answer of @Dane White is OK, first I did not like using Runnable but I could not find any alternatives.

Here another implementation I preferred more:

public class OptionalConsumer<T> {
    private Optional<T> optional;

    private OptionalConsumer(Optional<T> optional) {
        this.optional = optional;
    }

    public static <T> OptionalConsumer<T> of(Optional<T> optional) {
        return new OptionalConsumer<>(optional);
    }

    public OptionalConsumer<T> ifPresent(Consumer<T> c) {
        optional.ifPresent(c);
        return this;
    }

    public OptionalConsumer<T> ifNotPresent(Runnable r) {
        if (!optional.isPresent()) {
            r.run();
        }
        return this;
    }
}

Then:

Optional<Any> o = Optional.of(...);
OptionalConsumer.of(o).ifPresent(s -> System.out.println("isPresent " + s))
                .ifNotPresent(() -> System.out.println("! isPresent"));

Update 1:

the above solution for the traditional way of development when you have the value and want to process it but what if I want to define the functionality and the execution will be then, check below enhancement;

public class OptionalConsumer<T> implements Consumer<Optional<T>> {
private final Consumer<T> c;
private final Runnable r;

public OptionalConsumer(Consumer<T> c, Runnable r) {
    super();
    this.c = c;
    this.r = r;
}

public static <T> OptionalConsumer<T> of(Consumer<T> c, Runnable r) {
    return new OptionalConsumer(c, r);
}

@Override
public void accept(Optional<T> t) {
    if (t.isPresent()) {
        c.accept(t.get());
    }
    else {
        r.run();
    }
}

Then could be used as:

Consumer<Optional<Integer>> c = OptionalConsumer.of(
    System.out::println, 
    () -> System.out.println("Not fit")
);

IntStream.range(0, 100)
    .boxed()
    .map(i -> Optional.of(i)
    .filter(j -> j % 2 == 0))
    .forEach(c);

In this new code you have 3 things:

  1. can define the functionality before the existing of an object easy.
  2. not creating object reference for each Optional, only one, you have so less memory than less GC.
  3. it is implementing consumer for better usage with other components.

By the way, now its name is more descriptive it is actually Consumer<Optional<?>>

catch23
  • 17,519
  • 42
  • 144
  • 217
Bassem Reda Zohdy
  • 12,662
  • 3
  • 33
  • 39
  • 3
    Should use Optional.ofNullable(o) instead of Optional.of(o) – traeper Mar 08 '17 at 07:22
  • 2
    You need to use ofNullable if you are not sure if the value you are going to use have null or not and do not need to face NPE, and of in case that you are sure it is not null or you are do not care if get NPE. – Bassem Reda Zohdy Mar 09 '17 at 09:12
  • 1
    I think that class OptionalConsumer looks better than if/else in code. Thanks! :) – witek1902 Jul 26 '18 at 10:51
  • Becareful with using optionals as constructor parameters. if a null is used as input you may get null pointer exceptions all over again which defeats of using optionals in the first place. – ron Oct 22 '21 at 14:43
  • in this case you may use optional.ofNullable(), this have to be handled outside OptionalConsumer in example above I just used Optional.of(i) because am sure that value is not going to be null but in other case if you could get value as null you have to use optional.ofNullable() – Bassem Reda Zohdy Oct 29 '21 at 20:08
109

Java 9 introduces

ifPresentOrElse if a value is present, performs the given action with the value, otherwise performs the given empty-based action.

See excellent Optional in Java 8 cheat sheet.

It provides all answers for most use cases.

Short summary below

ifPresent() - do something when Optional is set

opt.ifPresent(x -> print(x)); 
opt.ifPresent(this::print);

filter() - reject (filter out) certain Optional values.

opt.filter(x -> x.contains("ab")).ifPresent(this::print);

map() - transform value if present

opt.map(String::trim).filter(t -> t.length() > 1).ifPresent(this::print);

orElse()/orElseGet() - turning empty Optional to default T

int len = opt.map(String::length).orElse(-1);
int len = opt.
    map(String::length).
    orElseGet(() -> slowDefault());     //orElseGet(this::slowDefault)

orElseThrow() - lazily throw exceptions on empty Optional

opt.
filter(s -> !s.isEmpty()).
map(s -> s.charAt(0)).
orElseThrow(IllegalArgumentException::new);
Bartosz Bilicki
  • 12,599
  • 13
  • 71
  • 113
  • 87
    This does not actually answer OP's question. It answers a lot of common uses but not what OP asked. – Captain Man May 15 '18 at 20:57
  • 1
    @CaptainMan actually it does; the opt.map("found").orElse("not found") expression fills the bill. – Matt Jun 27 '18 at 18:52
  • 7
    @Matt no, OP is specifically asking for actions to he performed when the optional is/is not present, not to return a value when it is or isn't. OP even mentions something similar in the question using orElseGet explaining why it won't work. – Captain Man Jun 28 '18 at 10:13
  • 2
    @CaptainMan I see your point. I do think he could make it work if he didn't return null from the `map`, but it is a bit strange to ask for a functional solution so you can call a DAO. Seems to me it would make more sense to return the updated/new object from this `map.orElse` block and then do what you need to do with the returned object. – Matt Jun 28 '18 at 17:12
  • 1
    I think `map` focus on the stream itself and is not intended for "doing things to another object depending on the status of this element in the stream". Good to know that `ifPresentOrElse` is added in Java 9. – WesternGun Oct 01 '18 at 10:32
  • Without java 9, which has `ifPresentOrElse()`, what op wants is not doable in a functional way, and nothing here helps. – Kalec Oct 17 '19 at 08:28
62

An alternative is:

System.out.println(opt.map(o -> "Found")
                      .orElse("Not found"));

I don't think it improves readability though.

Or as Marko suggested, use a ternary operator:

System.out.println(opt.isPresent() ? "Found" : "Not found");
assylias
  • 321,522
  • 82
  • 660
  • 783
  • 2
    Thanks @assylias , but I don't think Optional.map() works for the case ( see my context update ). – smallufo May 21 '14 at 16:30
  • 2
    @smallufo You would need to return `new Object();` in your first lambda but to be honest that becomes very ugly. I would stick to an if/else for your updated example. – assylias May 21 '14 at 17:09
  • Agree, using `map` to just return `Optional` for chaining makes the code harder to understand while `map` is assumed to literally map to something. – Tiina Jan 12 '19 at 09:27
47

Another solution would be to use higher-order functions as follows

opt.<Runnable>map(value -> () -> System.out.println("Found " + value))
   .orElse(() -> System.out.println("Not Found"))
   .run();
user5057016
  • 479
  • 4
  • 2
  • 11
    In my eyes the best solution so far without JDK 9. – Semaphor Feb 11 '16 at 07:20
  • 6
    An explanation would be great. I am asking myself, why you need to use the a runnable map (?) and what the `value -> () -> syso` part means. – froehli May 22 '17 at 10:54
  • Thanks for this solution! I think the reason of using Runnable is that out map doesn't return any value and with Runnable it returns lambda and such as result of map is lambda we run it after. So if you have returning value you can use the following: `String result = opt.map(value -> "withOptional").orElse("without optional");` – nanotexnik Nov 01 '17 at 18:30
23

There isn't a great way to do it out of the box. If you want to be using your cleaner syntax on a regular basis, then you can create a utility class to help out:

public class OptionalEx {
    private boolean isPresent;

    private OptionalEx(boolean isPresent) {
        this.isPresent = isPresent;
    }

    public void orElse(Runnable runner) {
        if (!isPresent) {
            runner.run();
        }
    }

    public static <T> OptionalEx ifPresent(Optional<T> opt, Consumer<? super T> consumer) {
        if (opt.isPresent()) {
            consumer.accept(opt.get());
            return new OptionalEx(true);
        }
        return new OptionalEx(false);
    }
}

Then you can use a static import elsewhere to get syntax that is close to what you're after:

import static com.example.OptionalEx.ifPresent;

ifPresent(opt, x -> System.out.println("found " + x))
    .orElse(() -> System.out.println("NOT FOUND"));
Dane White
  • 3,443
  • 18
  • 16
16

If you can use only Java 8 or lower:

1) if you don't have spring-data the best way so far is:

opt.<Runnable>map(param -> () -> System.out.println(param))
      .orElse(() -> System.out.println("no-param-specified"))
      .run();

Now I know it's not so readable and even hard to understand for someone, but looks fine for me personally and I don't see another nice fluent way for this case.

2) if you're lucky enough and you can use spring-data the best way is Optionals#ifPresentOrElse:

Optionals.ifPresentOrElse(opt, System.out::println,
      () -> System.out.println("no-param-specified"));

If you can use Java 9, you should definitely go with:

opt.ifPresentOrElse(System.out::println,
      () -> System.out.println("no-param-specified"));
Tyulpan Tyulpan
  • 724
  • 1
  • 7
  • 17
3

You cannot call orElse after ifPresent, the reason is, orElse is called on an optiional but ifPresent returns void. So the best approach to achieve is ifPresentOrElse. It could be like this:

op.ifPresentOrElse( 
            (value) 
                -> { System.out.println( 
                         "Value is present, its: "
                         + value); }, 
            () 
                -> { System.out.println( 
                         "Value is empty"); }); 
Dima Kozhevin
  • 3,602
  • 9
  • 39
  • 52
M.Khan
  • 41
  • 3
3

The problem here:

optional
  .map(object -> {
    System.out.println("If present.");
    return null;
  })
  .orElseGet( () -> {
    System.out.println("If empty.");
    return null;
  });

Is that map() converts the null returned by the first function to empty(); it then returns empty(). As it returns empty(), it prompts the invocation of the second function. Note that orElseGet() does not convert the null returned by the second function to empty(), so it will return null.

See the implementation of map():

public<U> Optional<U> map(Function<? super T, ? extends U> mapper) {
    Objects.requireNonNull(mapper);
    if (!isPresent())
        return empty();
    else {
        return Optional.ofNullable(mapper.apply(value));
    }
}

And the implementation of orElseGet():

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

Thus when executed:

  • if optional.isPresent(), the system will print If present., then If empty., and the expression will evaluate to null.

  • if !optional.isPresent(), the system will print If empty., and the expression will evaluate to null.


If the function provided to map() returned any other value - any other value - the code would work as you expect, with the function provided to map() being executed if isPresent() and the function provided to orElseGet() if !isPresent():

For example, this:

optional
  .map(data -> {
    System.out.println("If present.");
    return 0;
  })
  .orElseGet( () -> {
    System.out.println("If empty.");
    return 0;
  });

When executed:

  • if optional.isPresent(), the system will print If present., and the expression will evaluate to 0.

  • if !optional.isPresent(), the system will print If empty., and the expression will evaluate to 0.

If your specific case, I suggest that your insert and update methods return, say, the persisted object, or the id of the persisted object, or something similarly useful; then you can use code similar to this:

final Object persist = optional
  .map(object -> {
    System.out.println("If present.");
    return update(object);
  })
  .orElseGet( () -> {
    System.out.println("If empty.");
    return insert(new Object());
  });
drew
  • 2,949
  • 3
  • 25
  • 27
2

The described behavior can be achieved by using Vavr (formerly known as Javaslang), an object-functional library for Java 8+, that implements most of Scala constructs (being Scala a more expressive language with a way richer type system built on JVM). It is a very good library to add to your Java projects to write pure functional code.

Vavr provides the Option monad that provides functions to work with the Option type such as:

  • fold: to map the value of the option on both cases (defined/empty)
  • onEmpty: allows to execute a Runnable when option is empty
  • peek: allows to consume the value of the option (when defined).
  • and it is also Serializable on the contrary of Optional which means you can safely use it as method argument and instance member.

Option follows the monad laws at difference to the Java's Optional "pseudo-monad" and provides a richer API. And of course you can make it from a Java's Optional (and the other way around): Option.ofOptional(javaOptional) –Vavr is focused on interoperability.

Going to the example:

// AWESOME Vavr functional collections (immutable for the gread good :)
// fully convertible to Java's counterparts.
final Map<String, String> map = Map("key1", "value1", "key2", "value2");

final Option<String> opt = map.get("nonExistentKey"); // you're safe of null refs!
        
final String result = opt.fold(
        () -> "Not found!!!",                // Option is None
        val -> "Found the value: " + val     // Option is Some(val)
);

Moreover, all Vavr types are convertible to its Java counterparts, for the sake of the example: Optional javaOptional = opt.toJava(), very easy :) Of course the conversion also exists in the other way: Option option = Option.ofOptional(javaOptional).

N.B. Vavr offers a io.vavr.API class with a lot of convenient static methods =)

Further reading

Null reference, the billion dollar mistake

N.B. This is only a very little example of what Vavr offers (pattern matching, streams a.k.a. lazy evaluated lists, monadic types, immutable collections,...).

Gerard Bosch
  • 648
  • 1
  • 7
  • 18
1

Another solution could be following:

This is how you use it:

    final Opt<String> opt = Opt.of("I'm a cool text");
    opt.ifPresent()
        .apply(s -> System.out.printf("Text is: %s\n", s))
        .elseApply(() -> System.out.println("no text available"));

Or in case you in case of the opposite use case is true:

    final Opt<String> opt = Opt.of("This is the text");
    opt.ifNotPresent()
        .apply(() -> System.out.println("Not present"))
        .elseApply(t -> /*do something here*/);

This are the ingredients:

  1. Little modified Function interface, just for the "elseApply" method
  2. Optional enhancement
  3. A little bit of curring :-)

The "cosmetically" enhanced Function interface.

@FunctionalInterface
public interface Fkt<T, R> extends Function<T, R> {

    default R elseApply(final T t) {
        return this.apply(t);
    }

}

And the Optional wrapper class for enhancement:

public class Opt<T> {

    private final Optional<T> optional;

    private Opt(final Optional<T> theOptional) {
        this.optional = theOptional;
    }
    
    public static <T> Opt<T> of(final T value) {
        return new Opt<>(Optional.of(value));
    }

    public static <T> Opt<T> of(final Optional<T> optional) {
        return new Opt<>(optional);
    }
    
    public static <T> Opt<T> ofNullable(final T value) {
        return new Opt<>(Optional.ofNullable(value));
    }
    
    public static <T> Opt<T> empty() {
        return new Opt<>(Optional.empty());
    }

    private final BiFunction<Consumer<T>, Runnable, Void> ifPresent = (present, notPresent) -> {
        if (this.optional.isPresent()) {
            present.accept(this.optional.get());
        } else {
            notPresent.run();
        }
        return null;
    };

   private final BiFunction<Runnable, Consumer<T>, Void> ifNotPresent = (notPresent, present) -> {
        if (!this.optional.isPresent()) {
            notPresent.run();
        } else {
            present.accept(this.optional.get());
        }
        return null;
    };

    public Fkt<Consumer<T>, Fkt<Runnable, Void>> ifPresent() {
        return Opt.curry(this.ifPresent);
    }

    public Fkt<Runnable, Fkt<Consumer<T>, Void>> ifNotPresent() {
        return Opt.curry(this.ifNotPresent);
    }

    private static <X, Y, Z> Fkt<X, Fkt<Y, Z>> curry(final BiFunction<X, Y, Z> function) {
        return (final X x) -> (final Y y) -> function.apply(x, y);
    }
}

This should do the trick and could serve as a basic template how to deal with such requirements.

The basic idea here is following. In a non functional style programming world you would probably implement a method taking two parameter where the first is a kind of runnable code which should be executed in case the value is available and the other parameter is the runnable code which should be run in case the value is not available. For the sake of better readability, you can use curring to split the function of two parameter in two functions of one parameter each. This is what I basically did here.

Hint: Opt also provides the other use case where you want to execute a piece of code just in case the value is not available. This could be done also via Optional.filter.stuff but I found this much more readable.

Hope that helps!

Additional Info:

There is another way to have say "if then else" using currying:

public static <X, Y> Function<Predicate<X>, Function<Function<X, Y>, Function<Function<X, Y>, Y>>> ifThenElse(X input) {
  return (final Predicate<X> pred) -> (final Function<X, Y> ifPresent) -> (final Function<X, Y> ifNotPresent) -> pred.test(input) ? ifPresent.apply(input) : ifNotPresent.apply(input);
}

This way it is possible to say:

final String result = ifThenElse("fancy")
  .apply(input -> input.contains("fancy")) /* test      */
  .apply(input -> input.toUpperCase())     /* if-case   */
  .apply(input -> input.toLowerCase());    /* else-case */
Alessandro Giusa
  • 1,660
  • 15
  • 11
0

In case you want store the value:

Pair.of<List<>, List<>> output = opt.map(details -> Pair.of(details.a, details.b))).orElseGet(() -> Pair.of(Collections.emptyList(), Collections.emptyList()));
Jhutan Debnath
  • 505
  • 3
  • 13
  • 24
  • don't think that pair is the best solution. you could create some POJO for this reason. With Java 15 it could use records. – catch23 Jan 05 '21 at 23:34
0

Supposing that you have a list and avoiding the isPresent() issue (related with optionals) you could use .iterator().hasNext() to check if not present.

Hasta Dhana
  • 4,699
  • 7
  • 17
  • 26
Leandro Maro
  • 325
  • 1
  • 12