RequireNonNull: примеры (JAVA)

requireNonNull в Java: описание и подбор примеров
Раздел: Верификация (валидация)
requireNonNull(T obj): T

Общее описание

Метод Objects.requireNonNull из пакета java.util проверяет ссылку на null и возвращает её же, если значение не равно null. В противном случае генерируется исключение java.lang.NullPointerException. Метод используется для явной проверки входных параметров, полей и значений, возвращаемых из других компонентов, при необходимости снабжая исключение понятным сообщением.

Сигнатуры и поведение:

  • Objects.requireNonNull(T obj) - принимает один аргумент. Если obj не равен null, возвращает его, иначе выбрасывает NullPointerException без сообщения.
  • Objects.requireNonNull(T obj, String message) - при null выбрасывает NullPointerException с указанным текстом. Сообщение вычисляется до вызова метода, потому его формирование выполняется всегда.
  • Objects.requireNonNull(T obj, Supplier messageSupplier) - при null вызывает messageSupplier.get() и использует возвращённую строку в качестве текста исключения. Этот вариант обеспечивает ленивое формирование сообщения; supplier не вызывается, если объект не равен null. (Supplier-версия появилась в более поздних релизах; см. раздел изменения.)

Возвращаемое значение: при ненулевом аргументе метод возвращает тот же объект и может использоваться внутри выражений и для цепочек присвоений. При равном null генерируется java.lang.NullPointerException; текст исключения зависит от используемой перегрузки.

Типичные сценарии применения: проверка аргументов в конструкторах и методах API, защита от непредвиденных null в цепочках вызовов, выражение контрактов (preconditions) и упрощение диагностики при ошибках.

Короткие примеры

Примеры показывают основные перегрузки и результаты их работы.

1) Стандартная проверка без сообщения

import java.util.Objects;

String s = null;
Objects.requireNonNull(s);
Exception in thread "main" java.lang.NullPointerException
	at java.util.Objects.requireNonNull(Objects.java:203)
	... (stack trace)

2) Проверка с текстовым сообщением

String name = null;
Objects.requireNonNull(name, "name must not be null");
Exception in thread "main" java.lang.NullPointerException: name must not be null
	at java.util.Objects.requireNonNull(Objects.java:207)
	... (stack trace)

3) Ленивое сообщение через Supplier

String data = null;
Objects.requireNonNull(data, () -> "missing data for id=" + computeId());
// computeId() не будет вызван, если data не null
Exception in thread "main" java.lang.NullPointerException: missing data for id=42
	at java.util.Objects.requireNonNull(Objects.java:210)
	... (stack trace)

4) Использование в цепочке присвоений

class User {
  private final String name;
  User(String name) {
    this.name = Objects.requireNonNull(name, "name required");
  }
}
Создание экземпляра с null приводит к NullPointerException: name required

Аналоги в Java

Существуют похожие механизмы в стандартной библиотеке и популярных библиотеках:

  • Objects.requireNonNullElse и Objects.requireNonNullElseGet - возвращают альтернативное значение, если первый аргумент равен null. Удобны, когда требуется дефолт.
  • java.util.Optional - для явного представления возможного отсутствия значения; предпочтителен при необходимости выразить опциональность, а не бросать исключение.
  • com.google.common.base.Preconditions.checkNotNull (Guava) - функционально близок к requireNonNull, часто используется в кодовой базе, где уже применяется Guava; возвращает ссылку и при null бросает NullPointerException. В Guava сообщение формируется аналогично: есть ленивые и нежадные варианты.

Выбор зависит от контекста: если требуется немедленное падение при invalid input - requireNonNull или Preconditions.checkNotNull. Если нужно предоставить запасной объект - requireNonNullElse. Для API, где отсутствие значения - допустимая ситуация, лучше Optional.

Аналоги в других языках

Краткий обзор эквивалентов и отличий от Java-метода.

  • Kotlin
    val x: String? = null
    val y = requireNotNull(x) { "x missing" }
    Exception in thread "main" java.lang.IllegalArgumentException: x missing
    Отличие: requireNotNull бросает IllegalArgumentException, но есть оператор !!, который генерирует NullPointerException; Kotlin лучше интегрирован с системой nullable-типов.
  • C#
    string s = null;
    if (s == null) throw new ArgumentNullException(nameof(s));
    Unhandled Exception: System.ArgumentNullException: Value cannot be null. (Parameter 's')
    Отличие: используется ArgumentNullException с именем параметра; нет стандартной функции в BCL с теми же перегрузками.
  • Python
    s = None
    if s is None:
        raise TypeError('s must not be None')
    Traceback (most recent call last):
      ...
    TypeError: s must not be None
    Отличие: динамическая типизация, явной стандартной утилиты нет; чаще используют проверку и raise.
  • JavaScript
    let x = null;
    if (x == null) throw new TypeError('x required');
    Uncaught TypeError: x required
    Отличие: нет встроенной requireNonNull; можно использовать операторы ?? или проверять вручную.
  • Go
    var p *int = nil
    if p == nil {
        panic("p is nil")
    }
    panic: p is nil
    
    goroutine 1 [running]:
    ... (stack trace)
    Отличие: в Go часто возвращают ошибку вместо panics; проверки выполняются вручную.
  • PHP
    $x = null;
    if (is_null($x)) { throw new InvalidArgumentException('x required'); }
    Fatal error: Uncaught InvalidArgumentException: x required
    Отличие: чаще выбрасывают InvalidArgumentException или TypeError.
  • Lua
    local x = nil
    if x == nil then error('x required') end
    lua: script.lua:2: x required
    stack traceback:
    	... (stack trace)

Во многих языках проверка null/null-equivalent выполняется вручную и выбор типа исключения зависит от конвенций. В Java удобство requireNonNull в том, что метод возвращает значение и легко вложим в выражения.

Типичные ошибки

Частые проблемы при использовании и примеры.

1) Ненужное создание сообщения

Objects.requireNonNull(user, "user id=" + expensiveComputation());
expensiveComputation() выполняется всегда, даже если user не null - лишние затраты.

Решение: использовать вариант с Supplier, чтобы отложить вызов.

2) Передача null в messageSupplier

Objects.requireNonNull(obj, null); // второй аргумент равен null
Если вызвать перегрузку с Supplier и передать null в качестве supplier, при попытке получить сообщение будет NPE или поведение приведёт к NPE - передавать null вместо supplier нельзя.

3) Неправильный тип исключения для контрактов API

// ожидалось IllegalArgumentException, но используется requireNonNull
Objects.requireNonNull(param, "bad param");
В результате при нарушении контрактов вызывающий получает NullPointerException, хотя семантически более уместно ArgumentException/IllegalArgumentException.

4) Излишнее использование в местах, где null допустим

requireNonNull применяет строгую политику. Если null является валидным состоянием, проверка ломает логику. Нужно документировать контракт метода.

Изменения по версиям

  • Objects.requireNonNull(T obj) и Objects.requireNonNull(T obj, String message) добавлены в ранних Java-версиях (с появлением класса Objects в JDK7).
  • Перегрузка с Supplier (Objects.requireNonNull(T obj, Supplier messageSupplier)) появилась позднее (в JDK9 и выше), чтобы обеспечить ленивое формирование сообщения и избежать лишних затрат при ненулевых значениях.
  • В остальном семантика метода стабилизировалась и существенных изменений в поведении не происходило.

Расширенные и нетривиальные примеры

Несколько продвинутых сценариев применения с пояснениями.

1) Ленивое сообщение с форматированием только при ошибке

Пример java
String config = null;
Objects.requireNonNull(config, () -> String.format("config missing for profile=%s, host=%s", profileName(), hostName()));
// profileName() и hostName() вызываются только при null
Exception in thread "main" java.lang.NullPointerException: config missing for profile=dev, host=localhost
	... (stack trace)

2) Валидация коллекции внутри stream, с выводом детального сообщения о позиции

Пример java
List list = Arrays.asList("a", null, "c");
List safe = IntStream.range(0, list.size())
    .mapToObj(i -> Objects.requireNonNull(list.get(i), () -> "null at index " + i))
    .collect(Collectors.toList());
Exception in thread "main" java.lang.NullPointerException: null at index 1
	... (stack trace)

3) Использование в фабричном методе для безопасной инициализации

Пример java
public static Connection create(String url, String user) {
  Objects.requireNonNull(url, "url required");
  Objects.requireNonNull(user, "user required");
  return new Connection(url, user);
}
Если один из аргументов null, создание прерывается с понятным сообщением.

4) Комбинация с requireNonNullElse для резервного значения

Пример java
String primary = null;
String fallback = "default";
String result = Objects.requireNonNullElse(primary, fallback);
result = "default"

5) Интеграция с API, где требуется сохранить тип и избежать unchecked-приведений

Пример java
public  T mustNotBeNull(T value) {
  return Objects.requireNonNull(value);
}

Integer i = mustNotBeNull(5); // тип сохранён
i = 5

6) Предупреждение о побочных эффектах в supplier

Пример java
Objects.requireNonNull(obj, () -> {
  // избегать побочных эффектов; supplier вызывается только при ошибке
  logger.error("null detected");
  return "obj was null";
});
Если obj не null, логирование не произойдёт; если null, supplier выполнится.

7) Проверка полей в блоке инициализации для immutable-объекта

Пример java
public final class Pair {
  private final String a;
  private final String b;

  public Pair(String a, String b) {
    this.a = Objects.requireNonNull(a, "a required");
    this.b = Objects.requireNonNull(b, "b required");
  }
}

// корректное использование обеспечивает, что поля никогда не равны null
При попытке создать Pair с одним из null будет выброшено соответствующее исключение с текстом.

Эти примеры демонстрируют гибкость requireNonNull: метод удобен для краткой и выразительной проверки контрактов, при этом вариации с supplier помогают оптимизировать производительность и сформировать подробные сообщения только при ошибке.

джава requireNonNull function comments

En
RequireNonNull Checks that the specified object reference is not null