1

I have a nullable Map<String, String> myMap in my Java 8 class.

I need to fetch a value from the map based on the following condition.

  • get keyA;
  • if not present, get keyB;
  • if not present, get keyC.

I understand that Java 8's Optional<T> brings the required behavior. Is there a way to use Optional to elegantly get the data instead of using containsKey checks?

Alexander Ivanchenko
  • 25,667
  • 5
  • 22
  • 46
rsundhar
  • 115
  • 5
  • 1
    Optional is just a container for a possible value or null. You'll still have to check the map for your desired key. Keep it Simple Soldier. – Robert Harvey Mar 25 '22 at 17:37
  • 1
    Seems like you're looking for `Optional.ofNullable(myMap.get("keyA")).or(() -> Optional.ofNullable(myMap.get("keyB"))).or(() -> Optional.ofNullable(myMap.get("keyC")));`. But that is frowned upon as a use of optional. A better implementation could use a stream: `Stream.of("keyA", "keyB", "keyC").map(myMap::get).filter(Objects::nonNull).findFirst().orElse(null);` – ernest_k Mar 25 '22 at 17:47

3 Answers3

3

Building on Alexander Ivanchenko's answer, you could get the first non-null value from the map based on a series of alternate keys:

public static Optional<String> getValue(Map<String, String> map,
                                        String keyA, String... keys) {
    Optional<String> result = Optional.ofNullable(map.get(keyA));
    for (String key : keys) {
        if (result.isPresent()) break;
        result = result.or(() -> Optional.ofNullable(map.get(key)));
    }
    return result;
}

You could use the getOrDefault method of map, but something like

map.getOrDefault("keyA", map.getOrDefault("keyB", map.get("keyC")))

seems overly specific and complicated, and you still have to deal with the fact that neither keyA nor keyB nor keyC might be present, so you might still get null, and this has the performance penalty of looking up all three values from the map no matter which is returned.

It also only works for three keys.

David Conrad
  • 15,432
  • 2
  • 42
  • 54
1

No. There is no special integration of Optional with Maps.

More to the point, Optional does not support null values. Assuming that by "nullable map" you mean "a map that can contain null values", you can't possibly use Optional to distinguish between "null values that are in your map" and "values that aren't in your map at all." There is absolutely no way to use Optional helpfully in this scenario.

Louis Wasserman
  • 191,574
  • 25
  • 345
  • 413
1

You can get an Optional result of retrieving the value corresponding to one of the given keys from a Map containing nullable values by using Stream.ofNullable() and Optional.or().

Method Optional.or() expects a supplier of Optional which will be utilized only if this method was invoked on an empty optional.

public static Optional<String> getValue(Map<String, String> myMap,
                                        String keyA, String keyB, String keyC) {
    
    return Stream.ofNullable(myMap) // precaution for myMap == null
            .flatMap(map -> Stream.ofNullable(map.get(keyA)))
            .findFirst()
            .or(() -> Optional.ofNullable(myMap.get(keyB)))   // evaluated only if keyA is not present
            .or(() -> Optional.ofNullable(myMap.get(keyC)));  // evaluated only if both keyA and keyB are not present                
}

Note: the method above is meant to accommodate the safe fetching (as the question title states) and will return an empty Optional if all the given keys are absent or if one or more of them is mapped to a null value.

Alexander Ivanchenko
  • 25,667
  • 5
  • 22
  • 46