20

Java 9 introduces the requireNonNullElse and requireNonNullElseGet methods to the Objects class. Are these functionally any different to the Optional.ofNullable() orElse() and orElseGet() methods?

String foo = null;
Objects.requireNonNullElse(foo, "nonNull");//returns the string "nonNull"
Optional.ofNullable(foo).orElse("nonNull");//also returns the string "nonNull"

If they have no functional difference, why was the Objects one added now?

David says Reinstate Monica
  • 19,209
  • 22
  • 79
  • 122

2 Answers2

26

There is one minor difference in their behavior. Objects.requireNonNullElse() requires that one of the parameters be non-null, otherwise, a NullPointerException is thrown.

String foo = null, bar = null;
Optional.ofNullable(foo).orElse(bar); //returns a null value
Objects.requireNonNullElse(foo, bar); //throws a NullPointerException
Naman
  • 27,789
  • 26
  • 218
  • 353
David says Reinstate Monica
  • 19,209
  • 22
  • 79
  • 122
  • 4
    There is also the minor non-functional difference that the `Optional` version generates garbage *(unless JIT is smart enough to optimize that away)*. – Andreas Oct 02 '17 at 03:33
  • 3
    @Andreas JMH reports there is no allocation difference between `Optional.ofNullable().orElse()` and `Objects.requireNonNullElse()` – ZhekaKozlov Oct 02 '17 at 04:20
  • @ZhekaKozlov Only if `foo` is `null`, in which case `ofNullable()` returns the constant *empty* instance. Did you try JMH with a non-null `foo`? Because I took the question as asking what the functional difference is between the two for *any* value, not just the `null` value. – Andreas Oct 02 '17 at 06:43
  • 1
    @Andreas Yes, I used non-null `foo`. The allocation rate drops to zero when the method is hot. – ZhekaKozlov Oct 02 '17 at 07:40
4

The conceptual difference between choosing one over another is as explained in their documentation. It relies on the approach of an API consumer to choose which one of them is supposed to be used effectively by them.

Optional is container object which may or may not contain a non-null value.

A variable whose type is Optional should never itself be null; it should always point to an Optional instance.

This is a value-based class; use of identity-sensitive operations (including reference equality (==), identity hash code, or synchronization) on instances of Optional may have unpredictable results and should be avoided.

  • ofNullable

    returns an Optional with a present value if the specified value is non-null, otherwise an empty Optional

  • orElse

    returns the value if present otherwise, returns other.

Hence the following behaviour:

String foo = null;
=> Optional.ofNullable(foo).orElse("nonNull")
=> Optional.ofNullable(null).orElse("nonNull")
=> Optional.empty().orElse("nonNull")
=> return otherwise "nonNull"

same as it traverses

String foo = null, bar = null;
=> Optional.ofNullable(foo).orElse(bar);
=> Optional.ofNullable(null).orElse(bar);
=> Optional.empty().orElse(bar)
=> return otherwise 'bar'
=> returns null

Objects is a class consists of static utility methods for operating on objects, or checking certain conditions before an operation.

These utilities include null-safe or null-tolerant methods for computing the hash code of an object, returning a string for an object, comparing two objects, and checking if indexes or sub-range values are out-of-bounds.

  • requireNonNullElse

    returns the first argument if it is non-null and otherwise the second argument if it is non-null

Hence the difference in behaviour:

String foo = null;
=> Objects.requireNonNullElse(foo, "nonNull")
=> Objects.requireNonNullElse(null, "nonNull");

which further evaluates internally if requireNonNull("nonNull", "defaultObj") and then

=> returns "nonNull" since its a non-null value

now as it traverses

String foo = null, bar = null;
=> Objects.requireNonNullElse(foo, bar);
=> Objects.requireNonNullElse(null, bar);

It checks internally if requireNonNull(bar, "defaultObj") which then

=> throws a NullPointerException

As documented as well

throws NullPointerException - if both obj is null and defaultObj is null

Naman
  • 27,789
  • 26
  • 218
  • 353