1

What are best practices related to checking if the Map contains an element since Java 8? I want to check if the Map contains an element and based on it get the object or create a new one and put it into the map. The functional way seems to be too verbose.

final private static Map<Integer, BowlingBall> pool = new HashMap<>();
int number = 8;

Imperative way:

BowlingBall ballImperative = null;

if (pool.containsKey(number)) {
    ballImperative = pool.get(number);
} else {
    ballImperative = new BowlingBall(number);
    pool.put(number, ballImperative);
}

Functional way:

BowlingBall ballFunctional = pool.values().stream()
    .filter(k -> k.getNumber() == number)
    .findAny()
    .orElseGet(() -> new BowlingBall(number));

pool.put(number, ballFunctional);
Nikolas Charalambidis
  • 40,893
  • 16
  • 117
  • 183
marekmuratow
  • 394
  • 2
  • 13

4 Answers4

4
BowlingBall ballImperative =
    pool.computeIfAbsent(number, BowlingBall::new);

Much easier.

Andy Turner
  • 137,514
  • 11
  • 162
  • 243
4

Since Java 8, there are two new methods available for this purpose:

Map#putIfAbsent:

Map<String, String> map = new HashMap<>();
map.put("hello", "world");
map.putIfAbsent("hello", "Luiggi");
System.out.println(map.get("hello"));

Map#computeIfAbsent:

Map<String, String> map = new HashMap<>();
map.put("hello", "world");
map.computeIfAbsent("hello", s -> "Luiggi");
System.out.println(map.get("hello"));

The main difference between them is that the former evaluates the value to put before checking if the key already contains a value. The latter may be understood as a lazy set. Example:

public String createValue(String s) {
    System.out.println("value of s: " + s);
    return "hello " + s;
}


Map<String, String> map = new HashMap<>();
map.put("hello", "world");
//executing the line below will fire System.out.println from the method
map.putIfAbsent("hello", createValue("world"));
//executing the line below will not fire System.out.println from the method
map.computeIfAbsent("hello", s -> createValue("world"));
System.out.println(map.get("hello"));

For your case, the code can be reduced to:

pool.put(number, number -> new BowlingBall(number));
Luiggi Mendoza
  • 85,076
  • 16
  • 154
  • 332
3

There are more ways:

  1. Map::putIfAbsent

    Here takes place Map::putIfAbsent(K key, V value) instead of the Stream which computes the value and puts with the key to the map if the key is not present.

    map.putIfAbsent(1, new BollwingBall(number));
    
  2. Map::computeIfAbsent

    The alternative way is Map::computeIfAbsent(K key, Function<? super K,? extends V> mappingFunction) which uses a mapping function to compute the value from the key. Works on the same principle as the method above.

    map.putIfAbsent(1, integer -> new BowlingBall(integer)); // the value is computed 
                                                             // from the key
    map.putIfAbsent(1, BowlingBall::new);                    // the shortened version of 
                                                             // the one above
    
Nikolas Charalambidis
  • 40,893
  • 16
  • 117
  • 183
2

Make use of Map.computeIfAbsent().

From the doc:

If the specified key is not already associated with a value (or is mapped to null), attempts to compute its value using the given mapping function and enters it into this map unless null.

Eg:

BowlingBall ballImperative = 
          pool.computeIfAbsent(number, BowlingBall::new);
Pankaj Singhal
  • 15,283
  • 9
  • 47
  • 86