Використання requireNonNull()
в якості перших висловлювань у методі дозволяє ідентифікувати зараз / швидку причину винятку.
Трафік чітко вказує на те, що виняток було кинуто, як тільки було введено метод, оскільки абонент не дотримувався вимог / контракту.
Передача null
об'єкта іншому методу дійсно може спровокувати виняток за раз, але причину проблеми може бути складніше зрозуміти, оскільки виняток буде кинутий у конкретному виклику null
об'єкта, який може бути набагато далі.
Ось конкретний і реальний приклад, який показує, чому ми маємо віддавати перевагу швидкому Object.requireNonNull()
виходу з ладу, і, особливо, використовуючи чи будь-який спосіб здійснити недійсну перевірку параметрів, розроблених як не null
.
Припустимо, що Dictionary
клас , який складає LookupService
і List
з String
представляють слова , що містяться в. Ці поля призначені для НЕ null
і один з них передається в Dictionary
конструктор.
Тепер припустимо, що "погана" реалізація Dictionary
без null
перевірки у записі методу (ось такий конструктор):
public class Dictionary {
private final List<String> words;
private final LookupService lookupService;
public Dictionary(List<String> words) {
this.words = this.words;
this.lookupService = new LookupService(words);
}
public boolean isFirstElement(String userData) {
return lookupService.isFirstElement(userData);
}
}
public class LookupService {
List<String> words;
public LookupService(List<String> words) {
this.words = words;
}
public boolean isFirstElement(String userData) {
return words.get(0).contains(userData);
}
}
Тепер давайте звернемося до Dictionary
конструктора з null
посиланням на words
параметр:
Dictionary dictionary = new Dictionary(null);
// exception thrown lately : only in the next statement
boolean isFirstElement = dictionary.isFirstElement("anyThing");
JVM кидає NPE на цю заяву:
return words.get(0).contains(userData);
Виняток у потоці "main" java.lang.NullPointerException
на LookupService.isFirstElement (LookupService.javabilje)
у Dictionary.isFirstElement (Словник.java:15)
у Dictionary.main (Dictionary.java:22)
Виняток спрацьовує в LookupService
класі, тоді як походження його набагато раніше ( Dictionary
конструктор). Це робить загальний аналіз проблеми набагато менш очевидним.
Є words
null
? Є words.get(0) null
? Обидва? Чому один, другий чи, можливо, обидва null
? Це помилка кодування в Dictionary
(конструктор? Викликаний метод?)? Це помилка кодування в LookupService
? (конструктор? викликаний метод?)?
Нарешті, нам доведеться перевірити більше коду, щоб знайти джерело помилок, а в більш складному класі можливо навіть використовувати відладчик, щоб легше зрозуміти, що це сталося.
Але чому проста справа (відсутність нульової перевірки) стає складною проблемою?
Тому що ми дозволили початкову помилку / відсутність ідентифікувати за певним витоком компонентів для нижчих компонентів.
Уявіть, що це LookupService
була не локальна служба, а віддалений сервіс або бібліотека сторонньої сторони з малою інформацією про налагодження, або уявіть, що до цього не null
було виявлено 2 шари, а 4 або 5 шарів викликів об’єктів ? Проблему було б ще складніше проаналізувати.
Тож спосіб вигоди:
public Dictionary(List<String> words) {
this.words = Objects.requireNonNull(words);
this.lookupService = new LookupService(words);
}
Таким чином, немає головного болю: ми виключаємо випадок, як тільки це буде отримано:
// exception thrown early : in the constructor
Dictionary dictionary = new Dictionary(null);
// we never arrive here
boolean isFirstElement = dictionary.isFirstElement("anyThing");
Виняток у потоці "main" java.lang.NullPointerException
на java.util.Objects.requireNonNull (Objects.java:203)
у com.D Dictionary. (Словник.java:15)
на com.Dictionary.main (Dictionary.java:24)
Зауважте, що тут я проілюстрував проблему з конструктором, але виклик методу міг би мати те саме обмеження, що не стосується нуля.