Confusing or mistakenly using Optional.of() instead of Optional.ofNullable(), or vice versa, can lead to weird behaviors and even NullPointerException.
Check the following failed attempt to write a snippet of code to avoid NullPointerException:
// Avoid
public Optional<String> isbn(String bookId) {
// the fetched "isbn" can be null for the given "bookId"
String isbn = ...;
return Optional.of(isbn); // this throws NPE if "isbn" is null :(
}
But, most probably, we actually wanted to use ofNullable(), as follows:
// Prefer
public Optional<String> isbn(String bookId) {
// the fetched "isbn" can be null for the given "bookId"
String isbn = ...;
return Optional.ofNullable(isbn);
}
Using ofNullable() instead of of() is not a disaster, but it may cause some confusion and bring no value. Check the following code:
// Avoid
// ofNullable() doesn't add any value
return Optional.ofNullable("123-456-789");
// Prefer
return Optional.of("123-456-789"); // no risk to NPE
Here is another problem. Let's assume that we want to convert an empty String object into an empty Optional. We may think that the proper solution will rely on of(), as follows:
// Avoid
Optional<String> result = Optional.of(str)
.filter(not(String::isEmpty));
But remember that String can be null. This solution will work fine for empty or non-empty strings, but not for the null strings. Therefore, ofNullable() gives us the proper solution, as follows:
// Prefer
Optional<String> result = Optional.ofNullable(str)
.filter(not(String::isEmpty));