Raipe
Raipe

Reputation: 807

Optional.orElse: how to continue the stream?

I would like to use the Stream approach, but I feel that it is somewhat sub-optimal. I would like to avoid the confusing

.map(Optional::of)

Is it possible to make the method #2 below to avoid this extra confusion, is there a optional method I could use to achieve what I want?

// Either map can be null, empty, or have the value for key
Map<String,String> map1 =  
Map<String,String> map2 = 


// Method #1
String value1 = null;
if (map1 != null) {
   value1 = map1.get(key);
}

if (value1 == null) {
   if (map2 != null) {
      value1 = map2.get(key);
   }
}

if (value1 == null) value1 = "default";

// Method #2
String value2 = Optional.ofNullable(map1)
    .map(map -> map.get(key))
    .map(Optional::of)
    .orElse(Optional.ofNullable(map2).map(map -> map.get(key)))
    .orElse("default");


assertEquals(value1, value2);

I would like to have something like this:

Optional.ofNullable(map1)
    .map(map -> map.get(key))
    .orOptional(Optional.ofNullable(map2).map(map -> map.get(key)))
    .orElse("default");

Where orOptional would be something like: // If a value is present in this Optional return this optional, otherwise return fallback Optional orOptional(Optional fallback)

Edit 2018-10-15: To not get stuck on the fact that I used maps in the example, lets assume those are just some beans with getter for a value. Either bean can be null or the values returned by getters can be null.

Upvotes: 2

Views: 6762

Answers (2)

dehasi
dehasi

Reputation: 2773

you don't need

.map(map -> map.get(key))
        .map(Optional::of)

Optional.map also returns Optional. you can just write

Optional.ofNullable(map1)
                .map(map -> map.get(key))
                .orElseGet(() ->
                        Optional.ofNullable(map2)
                                .map(map -> map.get(key)).orElse("default")
                );

Also, you can create a stream of maps and then do some tranformations:

Stream.of(map1, map2)
  .filter(Objects::nonNull)
  .map(m -> m.get(key))
  .filter(Objects::nonNull)
  .findFirst()
  .orElse("default");

Upvotes: 2

Holger
Holger

Reputation: 298143

There is a fundamental design error in letting the map variables ever become null.

If you can’t fix the source of the maps, you should at least introduce local variables holding non-null maps as early as possible in your processing.

Map<String,String> m1 = map1 == null? Map.of(): map1, m2 = map2 == null? Map.of(): map2;

Map.of() requires Java 9. In Java 8, you can use Collections.emptyMap() instead.

Then, your task is as easy as

String value1 = m1.getOrDefault(key, m2.getOrDefault(key, "default"));

Upvotes: 1

Related Questions