skip to content

How do Objects.requireNonNullElse and Objects.toString(obj, default) provide null-safe defaults, and how do they differ from requireNonNull?

level: middleimportance: should knowfreq 50%

answer

  1. requireNonNullElse(x, d): x if non-null else d (throws if both null)
  2. requireNonNullElseGet(x, supplier): lazy default, built only on null
  3. toString(o): null -> "null"; toString(o, def): null -> def
  4. Default = tolerate null; requireNonNull = reject null
  5. Else is eager; ElseGet is lazy

basics

~20 s

requireNonNullElse(x, fallback) returns x if it's not null, otherwise the fallback - so you get a default instead of an exception. Objects.toString(obj, nullDefault) returns obj.toString() if obj isn't null, otherwise the given default string. Both substitute a value for null instead of throwing like requireNonNull does.

solid answer

~40 s

These are the 'supply a default' helpers, the complement of requireNonNull's 'reject null'. Objects.requireNonNullElse(obj, defaultObj) (Java 9+) returns obj if non-null, else defaultObj; it throws only if BOTH are null, so the default itself must be non-null. requireNonNullElseGet(obj, supplier) is the lazy variant - the supplier produces the default only when obj is null, avoiding eager allocation. Objects.toString(Object) returns "null" for a null argument (never throws), and the two-arg Objects.toString(obj, nullDefault) returns nullDefault instead when obj is null - handy for safe logging/display. The key mental split: use requireNonNull when null is a bug you want surfaced; use requireNonNullElse / toString-with-default when null is acceptable and you simply want a sensible substitute. Note requireNonNullElse eagerly evaluates the default argument; prefer the ...Get supplier form when the default is expensive to build.

code

java · 21 lines
java
import java.util.Objects;

class Defaults {
    String displayName(String input) {
        // Cheap constant default -> requireNonNullElse
        return Objects.requireNonNullElse(input, "anonymous");
    }

    Config config(Config maybe) {
        // Expensive default -> lazy supplier form (only runs if maybe == null)
        return Objects.requireNonNullElseGet(maybe, Defaults::loadDefaultConfig);
    }

    String logField(Object value) {
        // null -> "<none>" instead of NPE or the string "null"
        return Objects.toString(value, "<none>");
    }

    static Config loadDefaultConfig() { /* costly */ return new Config(); }
    static class Config {}
}

go deeper

for a junior

Knows requireNonNullElse gives a fallback instead of throwing, and Objects.toString handles null safely.

for a middle

Distinguishes else (eager) vs elseGet (lazy), knows the both-null throw, and picks default-vs-reject correctly.

for a senior

Weighs these against Optional.orElse/orElseGet, reasons about allocation/laziness, and avoids defaulting over real contract violations.

for a principal

Defines team policy on null tolerance vs enforcement across API layers and the readability/performance trade-offs of helpers vs Optional vs annotations.

## Two opposite responses to null When a value might be null you have two strategies: 1. **Reject it** - it's a contract violation, throw (that's `requireNonNull`). 2. **Substitute a default** - null is acceptable, just use a fallback. That's what this question covers. ## Objects.requireNonNullElse (Java 9+) ```java static <T> T requireNonNullElse(T obj, T defaultObj) ``` Returns `obj` if it is non-null; otherwise returns `defaultObj`. Important detail: if **both** `obj` and `defaultObj` are null, it throws `NullPointerException` - so the fallback is expected to be non-null (a null default is itself a bug). ```java String name = Objects.requireNonNullElse(input, "anonymous"); ``` If `input` is null you get `"anonymous"`; otherwise the input. This replaces the verbose `input != null ? input : "anonymous"`. **Caveat - eager evaluation.** Both arguments are evaluated before the call (normal Java argument evaluation). So `requireNonNullElse(x, buildExpensiveDefault())` always builds the default even when `x` is non-null. That can be wasteful. ## Objects.requireNonNullElseGet (Java 9+) - the lazy form ```java static <T> T requireNonNullElseGet(T obj, Supplier<? extends T> supplier) ``` Returns `obj` if non-null; otherwise calls `supplier.get()` to **lazily** produce the default. The supplier runs **only** when `obj` is null, so the expensive default is built only when actually needed: ```java Config c = Objects.requireNonNullElseGet(maybeConfig, () -> loadDefaultConfig()); ``` Rule of thumb: cheap constant default -> `requireNonNullElse`; expensive/side-effecting default -> `requireNonNullElseGet`. ## Objects.toString - null-safe stringification Two overloads: ```java static String toString(Object o) // null -> "null" static String toString(Object o, String nullDefault) // null -> nullDefault ``` - `Objects.toString(o)` never throws on null - it returns the literal string `"null"` instead of NPE-ing the way `o.toString()` would. - `Objects.toString(o, "-")` returns `o.toString()` when `o` is non-null, and your chosen default (`"-"`) when it's null. Great for log lines and UI where a null field should render as something readable rather than crash or show `"null"`. ```java log.info("user={}", Objects.toString(user, "<none>")); ``` ## How these differ from requireNonNull | Helper | On null... | Use when | |---|---|---| | `requireNonNull(x)` | **throws NPE** | null is a bug; fail fast | | `requireNonNullElse(x, d)` | returns `d` | null is OK; cheap default | | `requireNonNullElseGet(x, s)` | returns `s.get()` | null is OK; expensive default | | `toString(x, d)` | returns `d` (a String) | null is OK; producing display/log text | So `requireNonNull` is about **enforcing** an invariant; the others are about **tolerating** absence with a fallback. Picking the wrong one hides real bugs (defaulting where you should have thrown) or crashes on legitimate absence (throwing where a default was fine). ## Relationship to Optional `Optional.ofNullable(x).orElse(d)` and `Optional.ofNullable(x).orElseGet(s)` do the same job as `requireNonNullElse`/`...Get`. For a simple local default, the `Objects` helpers are lighter (no Optional allocation); `Optional` shines when you're chaining transformations (`map`, `filter`) or expressing 'may be absent' in a return type.

  • When should you choose requireNonNullElseGet over requireNonNullElse?
    When the default value is expensive or has side effects to construct. requireNonNullElse evaluates its default argument eagerly (always), while requireNonNullElseGet's supplier runs only when the primary value is null.
  • What's the difference between Objects.toString(o) and o.toString()?
    o.toString() throws NullPointerException if o is null; Objects.toString(o) returns the literal string "null" instead, and the two-arg form lets you supply your own default string for the null case.

saying these in an interview costs you the question

  • Thinking requireNonNullElse never throws (it does if both args are null)
  • Using requireNonNullElse with an expensive default (it's eagerly evaluated)
  • Assuming Objects.toString(null) throws (it returns "null")
  • Defaulting away a null that was actually a contract violation

context