241. Avoiding Optional in collections

Relying on Optional in collections can be a design smell. Take another 30 minutes to re-evaluate the problem and discover better solutions.

The preceding statement is valid especially in the case of Map when the reason behind this decision sounds like this—so,  Map returns null if there is no mapping for a key or if null is mapped to the key, so I cannot tell whether the key is not present or is a missing value. I will wrap the values via Optional.ofNullable() and done!

But what will we decide further if Map of Optional<Foo> is populated with null values, absent Optional values, or even Optional objects that contain something else, but not Foo? Haven't we just nested the initial problem into one more layer? How about the performance penalty? Optional is not cost free; it is just another object that consumes memory and needs to be collected.

So, let's consider a solution that should be avoided:

private static final String NOT_FOUND = "NOT FOUND";
...
// Avoid
Map<String, Optional<String>> isbns = new HashMap<>();
isbns.put("Book1", Optional.ofNullable(null));
isbns.put("Book2", Optional.ofNullable("123-456-789"));
...
Optional<String> isbn = isbns.get("Book1");

if (isbn == null) {
System.out.println("This key cannot be found");
} else {
String unwrappedIsbn = isbn.orElse(NOT_FOUND);
System.out.println("Key found, Value: " + unwrappedIsbn);
}

A better and elegant solution can rely on JDK 8, getOrDefault() as follows:

private static String get(Map<String, String> map, String key) {
return map.getOrDefault(key, NOT_FOUND);
}

Map<String, String> isbns = new HashMap<>();
isbns.put("Book1", null);
isbns.put("Book2", "123-456-789");
...
String isbn1 = get(isbns, "Book1"); // null
String isbn2 = get(isbns, "Book2"); // 123-456-789
String isbn3 = get(isbns, "Book3"); // NOT FOUND

Other solutions can rely on the following:

  • The containsKey() method
  • Trivial implementation by extending HashMap
  • The JDK 8 computeIfAbsent() method
  • Apache Commons DefaultedMap

We can conclude that there are always better solutions than using Optional in collections.

But the discussed use case from earlier is not the worst-case scenario. Here are two more that must be avoided:

Map<Optional<String>, String> items = new HashMap<>();
Map<Optional<String>, Optional<String>> items = new HashMap<>();
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.128.173.53