java проверка Избегание!=Null




object== null java (24)

Я использую object != null чтобы избежать NullPointerException .

Есть ли хорошая альтернатива этому?

Например:

if (someobject != null) {
    someobject.doCalc();
}

Это позволяет избежать NullPointerException , когда неизвестно, является ли объект null или нет.

Обратите внимание, что принятый ответ может быть устаревшим, см. https://stackoverflow.com/a/2386013/12943 для более позднего подхода.


С Java 8 появился новый класс java.util.Optional который, возможно, решает некоторые проблемы. Можно хотя бы сказать, что он улучшает читабельность кода, а в случае публичных API-интерфейсов упрощает работу с API-интерфейсом для клиентского разработчика.

Они работают так:

Необязательный объект для данного типа ( Fruit ) создается как возвращаемый тип метода. Он может быть пустым или содержать объект Fruit :

public static Optional<Fruit> find(String name, List<Fruit> fruits) {
   for (Fruit fruit : fruits) {
      if (fruit.getName().equals(name)) {
         return Optional.of(fruit);
      }
   }
   return Optional.empty();
}

Теперь посмотрите на этот код, где мы ищем список Fruit ( fruits ) для данного экземпляра Fruit:

Optional<Fruit> found = find("lemon", fruits);
if (found.isPresent()) {
   Fruit fruit = found.get();
   String name = fruit.getName();
}

Вы можете использовать оператор map() для выполнения вычисления на - или извлечения значения из - необязательного объекта. orElse() позволяет предоставить orElse() для отсутствующих значений.

String nameOrNull = find("lemon", fruits)
    .map(f -> f.getName())
    .orElse("empty-name");

Конечно, проверка нулевого / пустого значения по-прежнему необходима, но, по крайней мере, разработчик осознает, что значение может быть пустым и риск забыть проверить ограничен.

В API, построенном с нуля, с использованием Optional когда возвращаемое значение может быть пустым и возвращает простой объект только тогда, когда он не может быть null (соглашение), клиентский код может отказаться от нулевых проверок на значениях возвращаемых объектов ...

Конечно, Optional также может использоваться как аргумент метода, возможно, лучший способ указать необязательные аргументы, чем 5 или 10 методов перегрузки в некоторых случаях.

Optional предлагает другие удобные методы, такие как orElse которые позволяют использовать значение по умолчанию, и ifPresent который работает с лямбда-выражениями .

Я предлагаю вам прочитать эту статью (мой основной источник для написания этого ответа), в которой проблема NullPointerException (и вообще нулевого указателя) проблематична, а также (частичное) решение, предоставленное Optional , хорошо объяснено: Java Необязательные объекты .


Если вы используете (или планируете использовать) Java IDE, например JetBrains IntelliJ IDEA , Eclipse или Netbeans или инструмент, например findbugs, вы можете использовать аннотации для решения этой проблемы.

В принципе, у вас есть @Nullable и @NotNull .

Вы можете использовать в методе и параметрах, например:

@NotNull public static String helloWorld() {
    return "Hello World";
}

или же

@Nullable public static String helloWorld() {
    return "Hello World";
}

Второй пример не будет компилироваться (в IntelliJ IDEA).

Когда вы используете первую функцию helloWorld() в другом фрагменте кода:

public static void main(String[] args)
{
    String result = helloWorld();
    if(result != null) {
        System.out.println(result);
    }
}

Теперь компилятор IntelliJ IDEA скажет вам, что проверка бесполезна, так как функция helloWorld() не вернет значение null .

Использование параметра

void someMethod(@NotNull someParameter) { }

если вы напишете что-то вроде:

someMethod(null);

Это не скомпилируется.

Последний пример с использованием @Nullable

@Nullable iWantToDestroyEverything() { return null; }

Делая это

iWantToDestroyEverything().something();

И вы можете быть уверены, что этого не произойдет. :)

Это хороший способ позволить компилятору проверить что-то большее, чем обычно, и усилить ваши контракты. К сожалению, он не поддерживается всеми компиляторами.

В IntelliJ IDEA 10.5 и далее они добавили поддержку любых других реализаций @Nullable @NotNull .

См. Запись в блоге. Более гибкие и настраиваемые @ Nullable / @ NotNull аннотации .


Иногда у вас есть методы, которые работают с параметрами, которые определяют симметричную операцию:

a.f(b); <-> b.f(a);

Если вы знаете, что b никогда не может быть нулевым, вы можете просто поменять его. Это наиболее полезно для равных: вместо foo.equals("bar"); лучше делать "bar".equals(foo); ,


Я поклонник кода «fail fast». Спросите себя: вы делаете что-то полезное в случае, когда параметр равен нулю? Если у вас нет четкого ответа на то, что должен делать ваш код в этом случае ... То есть он никогда не должен быть нулевым, а затем игнорировать его и разрешать бросать NullPointerException. Вызывающий код будет иметь такое же значение NPE, как и исключение IllegalArgumentException, но разработчику будет легче отлаживать и понимать, что пошло не так, если NPE выбрано, а не ваш код, пытающийся выполнить некоторые другие непредвиденные непредвиденные обстоятельства логики, что в конечном итоге приводит к тому, что приложение все равно не работает.


Гува, очень полезная базовая библиотека от Google, имеет хороший и полезный API, чтобы избежать нулей. Я нахожу Guava очень полезным.

Как поясняется в wiki:

Optional<T>является способом замены нулевой ссылки T с ненулевым значением. Необязательный может либо содержать ненулевую ссылку T (в этом случае мы говорим, что ссылка «присутствует»), либо она может содержать ничего (в этом случае мы говорим, что ссылка «отсутствует»). Он никогда не говорил «содержать null».

Использование:

Optional<Integer> possible = Optional.of(5);
possible.isPresent(); // returns true
possible.get(); // returns 5

Вау, я почти не хочу добавлять еще один ответ, когда у нас есть 57 различных способов рекомендовать NullObject pattern , но я думаю, что некоторым людям, заинтересованным в этом вопросе, может понравиться знать, что в таблице для Java 7 есть предложение добавить «null -safe handling " - упрощенное синтаксис для логики if-not-equal-null.

Пример, данный Алексом Миллером, выглядит следующим образом:

public String getPostcode(Person person) {  
  return person?.getAddress()?.getPostcode();  
}  

?. означает только отмену ссылки на левый идентификатор, если он не является нулевым, иначе оценивайте остальную часть выражения как null . Некоторые люди, такие как член Джона Поссе Дик Уолл и избиратели из Devoxx, действительно любят это предложение, но есть и оппозиция, потому что это на самом деле будет способствовать более широкому использованию null в качестве дозорной ценности.

Обновление: proposed для оператора с нулевой безопасностью в Java 7 было представлено в Project Coin. Синтаксис немного отличается от приведенного выше примера, но это одно и то же понятие.

Обновление. Предложение с нулевым безопасным оператором не попало в проектную монету. Таким образом, вы не увидите этот синтаксис в Java 7.


В дополнение к использованию assertвы можете использовать следующее:

if (someobject == null) {
    // Handle null here then move on.
}

Это немного лучше, чем:

if (someobject != null) {
    .....
    .....



    .....
}

Вместо Null Object Pattern - который имеет свои применения - вы можете рассмотреть ситуации, когда нулевой объект является ошибкой.

Когда выбрано исключение, проверьте трассировку стека и выполните ошибку.


Если значения null не допускаются

Если ваш метод вызывается извне, начните с чего-то вроде этого:

public void method(Object object) {
  if (object == null) {
    throw new IllegalArgumentException("...");
  }

Затем, в остальной части этого метода, вы узнаете, что object не является нулевым.

Если это внутренний метод (не часть API), просто документируйте, что он не может быть нулевым, и все.

Пример:

public String getFirst3Chars(String text) {
  return text.subString(0, 3);
}

Однако, если ваш метод просто передает значение, а следующий метод передает его и т. Д., Это может стать проблематичным. В этом случае вы можете проверить аргумент, как указано выше.

Если null разрешен

Это действительно зависит. Если вы обнаружите, что я часто делаю что-то вроде этого:

if (object == null) {
  // something
} else {
  // something else
}

Поэтому я развожу и делаю две совершенно разные вещи. Существует не уродливый фрагмент кода, потому что мне действительно нужно делать две разные вещи в зависимости от данных. Например, должен ли я работать с вводом, или я должен рассчитать хорошее значение по умолчанию?

Для меня действительно редко используется идиома « if (object != null && ... ».

Вам может быть проще привести примеры, если вы покажете примеры того, где вы обычно используете идиому.


Мне нравятся статьи из Nat Pryce. Вот ссылки:

В статьях есть также ссылка на репозиторий Git для Java Maybe Type, который я нахожу интересным, но я не думаю, что это само по себе может уменьшить разбухание кода проверки. После некоторых исследований в Интернете, я думаю ! = Нулевой код bloat может быть уменьшен главным образом путем тщательного проектирования.


Это для меня звучит как довольно распространенная проблема, с которой младшие и средние разработчики склонны сталкиваться в какой-то момент: они либо не знают, либо не доверяют контрактам, в которых они участвуют, и оборонительно переоценивают нулевые значения. Кроме того, при написании собственного кода они склонны полагаться на возврат нулей, чтобы указать что-то, что требует от вызывающего пользователя проверки нулей.

Иными словами, есть два случая, когда возникает нулевая проверка:

  1. Если null - действительный ответ в терминах контракта; а также

  2. Если это недействительный ответ.

(2) легко. Используйте либо assert (утверждения), либо разрешите сбой (например, NullPointerException ). Утверждения - это очень малоиспользуемая функция Java, добавленная в 1.4. Синтаксис:

assert <condition>

или же

assert <condition> : <object>

где <condition> является логическим выражением, а <object> - это объект, чей вывод метода toString() будет включен в ошибку.

Оператор assert выдает Error ( AssertionError ), если условие не соответствует действительности. По умолчанию Java игнорирует утверждения. Вы можете включить утверждения, передав опцию -ea в JVM. Вы можете включать и отключать утверждения для отдельных классов и пакетов. Это означает, что вы можете проверить код с помощью утверждений при разработке и тестировании и отключить их в рабочей среде, хотя мое тестирование показало рядом с отсутствием влияния производительности на утверждения.

Не использовать утверждения в этом случае - это нормально, потому что код будет просто терпеть неудачу, что и произойдет, если вы используете утверждения. Единственное различие заключается в том, что с утверждениями это может произойти раньше, более значимым образом и, возможно, с дополнительной информацией, которая может помочь вам разобраться, почему это произошло, если вы этого не ожидали.

(1) немного сложнее. Если у вас нет контроля над кодом, который вы вызываете, вы застряли. Если null является допустимым ответом, вы должны проверить его.

Однако если это код, который вы контролируете, (и это часто бывает), то это совсем другая история. Избегайте использования нулей в качестве ответа. С помощью методов, возвращающих коллекции, легко: возвращать пустые коллекции (или массивы) вместо нулей в значительной степени все время.

С не-коллекциями это может быть сложнее. Рассмотрим это как пример: если у вас есть эти интерфейсы:

public interface Action {
  void doSomething();
}

public interface Parser {
  Action findAction(String userInput);
}

где Parser берет необработанный пользовательский ввод и находит что-то делать, возможно, если вы реализуете интерфейс командной строки для чего-то. Теперь вы можете сделать контракт, что он возвращает null, если нет соответствующего действия. Это приводит к нулевой проверке, о которой вы говорите.

Альтернативное решение - никогда не возвращать null и вместо этого использовать шаблон Null Object :

public class MyParser implements Parser {
  private static Action DO_NOTHING = new Action() {
    public void doSomething() { /* do nothing */ }
  };

  public Action findAction(String userInput) {
    // ...
    if ( /* we can't find any actions */ ) {
      return DO_NOTHING;
    }
  }
}

Для сравнения:

Parser parser = ParserFactory.getParser();
if (parser == null) {
  // now what?
  // this would be an example of where null isn't (or shouldn't be) a valid response
}
Action action = parser.findAction(someInput);
if (action == null) {
  // do nothing
} else {
  action.doSomething();
}

в

ParserFactory.getParser().findAction(someInput).doSomething();

что намного лучше, потому что это приводит к более сжатому коду.

Тем не менее, возможно, вполне применимо, чтобы метод findAction () выдавал исключение со значимым сообщением об ошибке - особенно в этом случае, когда вы полагаетесь на ввод пользователя. Было бы намного лучше, если метод findAction выбрал исключение, чем для вызывающего метода, чтобы взорвать простое исключение NullPointerException без объяснения причин.

try {
    ParserFactory.getParser().findAction(someInput).doSomething();
} catch(ActionNotFoundException anfe) {
    userConsole.err(anfe.getMessage());
}

Или, если вы считаете, что механизм try / catch слишком уродлив, а не Do Nothing, ваше действие по умолчанию должно обеспечивать обратную связь с пользователем.

public Action findAction(final String userInput) {
    /* Code to return requested Action if found */
    return new Action() {
        public void doSomething() {
            userConsole.err("Action not found: " + userInput);
        }
    }
}

Я очень пренебрегаю ответами, которые предполагают использование нулевых объектов в каждой ситуации. Этот шаблон может разорвать контракт и похоронить проблемы глубже и глубже, вместо того, чтобы решать их, не говоря уже о том, что использование неправомерно создаст еще одну кучу кода шаблона, который потребует дальнейшего обслуживания.

В действительности, если что-то, возвращаемое из метода, может быть нулевым, а вызывающий код должен принять решение, должен быть более ранний вызов, который обеспечивает состояние.

Также имейте в виду, что шаблон нулевого объекта будет голоден, если использовать его без осторожности. Для этого - экземпляр NullObject должен делиться между владельцами, а не быть экземпляром unigue для каждого из них.

Кроме того, я бы не рекомендовал использовать этот шаблон, где тип должен быть представлением примитивного типа, как математические объекты, которые не являются скалярами: векторами, матрицами, комплексными числами и объектами POD (простые старые данные), которые предназначены для хранения состояния в виде встроенных типов Java. В последнем случае вы в конечном итоге вызываете методы getter с произвольными результатами. Например, что должен вернуть метод NullPerson.getName ()?

Стоит рассмотреть такие случаи, чтобы избежать абсурдных результатов.


Просто никогда не используйте null. Не допускайте этого.

В моих классах большинство полей и локальных переменных имеют значения, отличные от нуля, и я добавляю в код условия контракта (всегда утверждаю) в коде, чтобы убедиться, что это принудительно (поскольку оно более кратким и более выразительным, чем позволяет выходят как NPE, а затем должны разрешить номер строки и т. д.).

Как только я принял эту практику, я заметил, что проблемы, похоже, закрепились. Вы случайно поймали вещи в процессе разработки и осознали, что у вас слабое место .. и что еще более важно .. он помогает инкапсулировать проблемы с различными модулями, разные модули могут «доверять» друг другу и не более засорять код с if = null elseконструкциями!

Это защитное программирование и в конечном итоге приводит к значительно более чистому коду. Всегда дезинфицируйте данные, например, здесь, применяя жесткие стандарты, и проблемы уходят.

class C {
    private final MyType mustBeSet;
    public C(MyType mything) {
       mustBeSet=Contract.notNull(mything);
    }
   private String name = "<unknown>";
   public void setName(String s) {
      name = Contract.notNull(s);
   }
}


class Contract {
    public static <T> T notNull(T t) { if (t == null) { throw new ContractException("argument must be non-null"); return t; }
}

Контракты похожи на тесты на мини-модулях, которые всегда работают, даже в производстве, и когда все терпит неудачу, вы знаете, почему, а не случайный NPE, вам нужно как-то понять.


public static <T> T ifNull(T toCheck, T ifNull) {
    if (toCheck == null) {
           return ifNull;
    }
    return toCheck;
}

Java 7 имеет новый класс утилиты java.util.Objects для которого существует метод requireNonNull() .Все это делает throw, NullPointerExceptionесли его аргумент равен null, но он немного очищает код. Пример:

Objects.requireNonNull(someObject);
someObject.doCalc();

Этот метод наиболее полезен для checking непосредственно перед назначением в конструкторе, где каждое его использование может сохранять три строки кода:

Parent(Child child) {
   if (child == null) {
      throw new NullPointerException("child");
   }
   this.child = child;
}

становится

Parent(Child child) {
   this.child = Objects.requireNonNull(child, "child");
}

Могу ли я ответить на это в более общем плане!

Мы обычно сталкиваемся с этой проблемой, когда методы получают параметры так, как мы не ожидали (плохой вызов метода - ошибка программиста). Например: вы ожидаете получить объект, вместо этого вы получите нуль. Вы ожидаете получить строку с хотя бы одним символом, вместо этого вы получите пустую строку ...

Таким образом, нет никакой разницы между:

if(object == null){
   //you called my method badly!

}

или же

if(str.length() == 0){
   //you called my method badly again!
}

Они оба хотят удостовериться, что мы получили действительные параметры, прежде чем будем выполнять какие-либо другие функции.

Как упоминалось в некоторых других ответах, чтобы избежать описанных выше проблем, вы можете следовать шаблону « Дизайн по контракту» . См. http://en.wikipedia.org/wiki/Design_by_contract .

Чтобы реализовать этот шаблон в java, вы можете использовать аннотации ядра java, такие как javax.annotation.NotNull или использовать более сложные библиотеки, такие как Hibernate Validator .

Просто образец:

getCustomerAccounts(@NotEmpty String customerId,@Size(min = 1) String accountType)

Теперь вы можете безопасно развить основную функцию вашего метода без необходимости проверки входных параметров, они защищают ваши методы от неожиданных параметров.

Вы можете сделать еще один шаг и убедиться, что в приложении могут быть созданы только действительные pojos. (образец с сайта валидатора спящего режима)

public class Car {

   @NotNull
   private String manufacturer;

   @NotNull
   @Size(min = 2, max = 14)
   private String licensePlate;

   @Min(2)
   private int seatCount;

   // ...
}

Это очень распространенная проблема для каждого разработчика Java. Таким образом, в Java 8 есть официальная поддержка для решения этих проблем без загроможденного кода.

Java 8 представила java.util.Optional<T>. Это контейнер, который может содержать или не содержать ненулевое значение. Java 8 предоставил более безопасный способ обработки объекта, значение которого может быть нулевым в некоторых случаях. Это вдохновлено идеями Haskell и Scala .

В двух словах класс Option включает методы для явного рассмотрения случаев, когда значение присутствует или отсутствует. Однако преимущество по сравнению с нулевыми ссылками заключается в том, что необязательный класс <T> заставляет вас думать о случае, когда значение отсутствует. Как следствие, вы можете предотвратить непреднамеренные исключения нулевого указателя.

В приведенном выше примере у нас есть фабрика домашних услуг, которая возвращает дескриптор нескольких устройств, доступных в доме. Но эти услуги могут быть или не быть доступными / функциональными; это означает, что это может привести к исключению NullPointerException. Вместо того, чтобы добавлять нулевое ifусловие перед использованием какой-либо службы, давайте обернем ее в Необязательный <Сервис>.

ОБРАЩЕНИЕ К ОПЦИИ <T>

Рассмотрим способ получения справки о сервисе с завода. Вместо того, чтобы возвращать служебную ссылку, оберните ее опцией. Он позволяет пользователю API знать, что возвращенная услуга может быть или не быть доступной / функциональной, использовать защитно

public Optional<Service> getRefrigertorControl() {
      Service s = new  RefrigeratorService();
       //...
      return Optional.ofNullable(s);
   }

Как вы видите, Optional.ofNullable()это простой способ получить ссылку. Есть еще один способ получить ссылку Необязательный, либо Optional.empty()& Optional.of(). Один для возврата пустого объекта вместо того, чтобы перенастраивать нуль, а другой - для обертывания объекта, не подлежащего обнулению, соответственно.

ТАК КАК ЭТО ТОГО, ЧТОБЫ ИЗБЕЖАТЬ НУЛЬНОЙ ПРОВЕРКИ?

После того, как вы завернули ссылочный объект, необязательно предоставляет множество полезных методов для вызова методов на завернутой ссылке без NPE.

Optional ref = homeServices.getRefrigertorControl();
ref.ifPresent(HomeServices::switchItOn);

Необязательный.ifPresent вызывает данный потребитель со ссылкой, если он является ненулевым значением. В противном случае он ничего не делает.

@FunctionalInterface
public interface Consumer<T>

Представляет операцию, которая принимает один входной аргумент и не возвращает результат. В отличие от большинства других функциональных интерфейсов, потребитель, как ожидается, будет работать через побочные эффекты. Это так чисто и легко понять. В приведенном выше примере кода HomeService.switchOn(Service)вызывается, если ссылка необязательного удержания не равна нулю.

Мы используем тернарный оператор очень часто для проверки нулевого условия и возврата альтернативного значения или значения по умолчанию. Опция предоставляет другой способ обработки одного и того же условия без проверки нулевого значения. Необязательный.orElse (defaultObj) возвращает defaultObj, если опция имеет нулевое значение. Давайте используем это в нашем примере кода:

public static Optional<HomeServices> get() {
    service = Optional.of(service.orElse(new HomeServices()));
    return service;
}

Теперь HomeServices.get () делает то же самое, но лучше. Он проверяет, уже ли инициализирована услуга. Если это тогда, верните то же самое или создайте новую новую услугу. Необязательный <T> .orElse (T) помогает вернуть значение по умолчанию.

Наконец, вот наш NPE, а также нулевой код без кода:

import java.util.Optional;
public class HomeServices {
    private static final int NOW = 0;
    private static Optional<HomeServices> service;

public static Optional<HomeServices> get() {
    service = Optional.of(service.orElse(new HomeServices()));
    return service;
}

public Optional<Service> getRefrigertorControl() {
    Service s = new  RefrigeratorService();
    //...
    return Optional.ofNullable(s);
}

public static void main(String[] args) {
    /* Get Home Services handle */
    Optional<HomeServices> homeServices = HomeServices.get();
    if(homeServices != null) {
        Optional<Service> refrigertorControl = homeServices.get().getRefrigertorControl();
        refrigertorControl.ifPresent(HomeServices::switchItOn);
    }
}

public static void switchItOn(Service s){
         //...
    }
}

Полный пост - это NPE, а также Null check-free code ... Действительно? ,


Обычная «проблема» в Java действительно.

Во-первых, мои мысли об этом:

Я считаю, что плохо «есть» что-то, когда был отправлен NULL, где NULL не является допустимым значением. Если вы не выходите из метода с какой-то ошибкой, значит, в вашем методе ничего не получилось, что неверно. Тогда вы, вероятно, вернете null в этом случае, а в методе получения вы снова проверите значение null, и оно никогда не закончится, и вы получите «if! = Null» и т. Д.

Таким образом, IMHO, null должен быть критической ошибкой, которая предотвращает дальнейшее выполнение (то есть, где null не является допустимым значением).

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

Во-первых, я следую этому соглашению:

  1. Все общедоступные методы / API всегда проверяют свои аргументы на нуль
  2. Все частные методы не проверяют значение null, поскольку они управляются методами (просто дайте умереть с исключением nullpointer в случае, если он не был обработан выше)
  3. Единственными другими методами, которые не проверяют значение null, являются утилиты. Они публичные, но если вы их почему-то называете, вы знаете, какие параметры вы передаете. Это похоже на попытку кипятить воду в чайнике без подачи воды ...

И, наконец, в коде первая строка общедоступного метода выглядит следующим образом:

ValidationUtils.getNullValidator().addParam(plans, "plans").addParam(persons, "persons").validate();

Обратите внимание, что addParam () возвращает self, так что вы можете добавить дополнительные параметры для проверки.

Метод validate()будет выдавать флажок, ValidationExceptionесли какой-либо из параметров имеет значение null (отмеченный или не отмеченный флажок - это проблема дизайна / вкуса, но моя ValidationExceptionпроверка).

void validate() throws ValidationException;

Сообщение будет содержать следующий текст, если, например, «plans» имеет значение NULL:

« Недопустимое значение аргумента null встречается для параметра [plans] "

Как вы можете видеть, второе значение в методе addParam () (строка) необходимо для сообщения пользователя, потому что вы не можете легко обнаружить имя переменной pass-in, даже с отражением (в любом случае это не относится к этому сообщению ...).

И да, мы знаем, что за этой строкой мы больше не будем сталкиваться с нулевым значением, поэтому просто безопасно вызываем методы для этих объектов.

Таким образом, код чист, прост в обслуживании и читабельности.


  • Если вы считаете, что объект не должен быть нулевым (или это ошибка), используйте assert.
  • Если ваш метод не принимает нулевые параметры, скажите это в javadoc и используйте assert.

Вы должны проверить объект! = Null, только если вы хотите обработать случай, когда объект может быть пустым ...

Есть предложение добавить новые аннотации в Java7, чтобы помочь с параметрами null / notnull: http://tech.puredanger.com/java7/#jsr308


Нуль - это не проблема. Он является неотъемлемой частью complete набора инструментов моделирования. Программное обеспечение нацелено на моделирование сложности мира, и нуль несет его бремя. Null указывает «Нет данных» или «Неизвестно» на Java и тому подобное. Поэтому для этих целей целесообразно использовать nulls. Я не предпочитаю шаблон «Нулевой объект»; Я думаю, что он поднимает « кто будет охранять проблему опекунов ».
Если вы спросите меня, как зовут мою подругу, я скажу вам, что у меня нет подруги. На языке Java я верну null. Альтернативой было бы вывести осмысленное исключение, чтобы указать на какую-то проблему, которая не может быть (или дон-t хотят быть), и там делегировать его куда-то выше в стеке, чтобы повторить попытку или сообщить об ошибке доступа к данным пользователю.

  1. Для «неизвестного вопроса» дайте «неизвестный ответ». (Небезопасно, если это правильно с бизнес-точки зрения). Проверка аргументов для null один раз внутри метода до использования освобождает нескольких вызывающих лиц от проверки их перед вызовом.

    public Photo getPhotoOfThePerson(Person person) {
        if (person == null)
            return null;
        // Grabbing some resources or intensive calculation
        // using person object anyhow.
    }
    

    Предыдущий приводит к нормальному логическому потоку, чтобы получить фотографию несуществующей подруги из моей фотобиблиотеки.

    getPhotoOfThePerson(me.getGirlfriend())
    

    И это соответствует новому API Java (с нетерпением ждущего)

    getPhotoByName(me.getGirlfriend()?.getName())
    

    Хотя довольно «нормальный бизнес-поток» не позволяет найти фотографию, хранящуюся в БД для какого-то человека, я использовал пару, как показано ниже, для некоторых других случаев

    public static MyEnum parseMyEnum(String value); // throws IllegalArgumentException
    public static MyEnum parseMyEnumOrNull(String value);
    

    И не мешайте типу <alt> + <shift> + <j>(генерировать javadoc в Eclipse) и пишите три дополнительных слова для публичного API. Этого будет более чем достаточно для всех, кроме тех, кто не читает документацию.

    /**
     * @return photo or null
     */
    

    или же

    /**
     * @return photo, never null
     */
    
  2. Это довольно теоретический случай, и в большинстве случаев вам следует предпочесть Java API с нулевым безопасностью (в случае, если он будет выпущен еще через 10 лет), но NullPointerExceptionявляется подклассом a Exception. Таким образом, это форма, Throwableкоторая указывает условия, которые разумное приложение может захотеть поймать ( javadoc )! Чтобы использовать первое преимущество использования исключений и отдельный код обработки ошибок из «обычного» кода ( согласно создателям Java ), уместно, как и для меня, поймать NullPointerException.

    public Photo getGirlfriendPhoto() {
        try {
            return appContext.getPhotoDataSource().getPhotoByName(me.getGirlfriend().getName());
        } catch (NullPointerException e) {
            return null;
        }
    }
    

    Могут возникнуть вопросы:

    Q. Что, если getPhotoDataSource()возвращает null?
    О. Это деловая логика. Если мне не удастся найти фотоальбом, я покажу вам никаких фотографий. Что делать, если appContext не инициализирован? Бизнес-логика этого метода справляется с этим. Если одна и та же логика должна быть более строгой, то бросание исключения является частью бизнес-логики, а явная проверка на нуль должна использоваться (случай 3). Новый Java Null-безопасный API лучше подходит здесь , чтобы указать выборочно , что подразумевает и то , что не означает быть инициализирован , чтобы быть не в состоянии , быстро в случае ошибок программиста.

    Q. Резервный код может быть выполнен и ненужные ресурсы могут быть захвачены.
    О. Это может произойти, если getPhotoByName()попытаться открыть соединение с базой данных, создать PreparedStatementи использовать имя человека в качестве параметра SQL. Подход к неизвестному вопросу дает неизвестный ответ (случай 1). Перед захватом ресурсов метод должен проверять параметры и при необходимости возвращать «неизвестный» результат.

    Q. Этот подход имеет штраф за производительность из-за открытия закрытия попытки.
    A. Программное обеспечение должно быть легко понятным и модифицированным во-первых. Только после этого можно было подумать о производительности, и только в случае необходимости! и там, где это необходимо! ( source ) и многие другие).

    PS.Такой подход будет разумным использовать, поскольку отдельный код обработки ошибок из «обычного» принципа кода разумно использовать в некотором месте. Рассмотрим следующий пример:

    public SomeValue calculateSomeValueUsingSophisticatedLogic(Predicate predicate) {
        try {
            Result1 result1 = performSomeCalculation(predicate);
            Result2 result2 = performSomeOtherCalculation(result1.getSomeProperty());
            Result3 result3 = performThirdCalculation(result2.getSomeProperty());
            Result4 result4 = performLastCalculation(result3.getSomeProperty());
            return result4.getSomeProperty();
        } catch (NullPointerException e) {
            return null;
        }
    }
    
    public SomeValue calculateSomeValueUsingSophisticatedLogic(Predicate predicate) {
        SomeValue result = null;
        if (predicate != null) {
            Result1 result1 = performSomeCalculation(predicate);
            if (result1 != null && result1.getSomeProperty() != null) {
                Result2 result2 = performSomeOtherCalculation(result1.getSomeProperty());
                if (result2 != null && result2.getSomeProperty() != null) {
                    Result3 result3 = performThirdCalculation(result2.getSomeProperty());
                    if (result3 != null && result3.getSomeProperty() != null) {
                        Result4 result4 = performLastCalculation(result3.getSomeProperty());
                        if (result4 != null) {
                            result = result4.getSomeProperty();
                        }
                    }
                }
            }
        }
        return result;
    }
    

    PPS. Для тех, кто быстро сжимается (и не так быстро читает документацию), я хотел бы сказать, что в своей жизни я никогда не видел исключения с нулевым указателем (NPE). Но эта возможность была специально разработана разработчиками Java, потому что NPE является подклассом Exception. У нас есть прецедент в истории Java, когда ThreadDeathэто Errorне так, потому что это на самом деле ошибка приложения, но только потому, что он не предназначен для того, чтобы быть пойманным! Сколько NPE подходит, чтобы быть Errorчем ThreadDeath! Но это не так.

  3. Проверьте «Нет данных» только в том случае, если это подразумевает бизнес-логика.

    public void updatePersonPhoneNumber(Long personId, String phoneNumber) {
        if (personId == null)
            return;
        DataSource dataSource = appContext.getStuffDataSource();
        Person person = dataSource.getPersonById(personId);
        if (person != null) {
            person.setPhoneNumber(phoneNumber);
            dataSource.updatePerson(person);
        } else {
            Person = new Person(personId);
            person.setPhoneNumber(phoneNumber);
            dataSource.insertPerson(person);
        }
    }
    

    а также

    public void updatePersonPhoneNumber(Long personId, String phoneNumber) {
        if (personId == null)
            return;
        DataSource dataSource = appContext.getStuffDataSource();
        Person person = dataSource.getPersonById(personId);
        if (person == null)
            throw new SomeReasonableUserException("What are you thinking about ???");
        person.setPhoneNumber(phoneNumber);
        dataSource.updatePerson(person);
    }
    

    Если appContext или dataSource не инициализируется необработанной рабочей средой, NullPointerException убьет текущий поток и будет обработан Thread.defaultUncaughtExceptionHandler (для определения и использования вашего любимого регистратора или другого Thread.defaultUncaughtExceptionHandler уведомления). Если не задано, ThreadGroup#uncaughtException будет печатать stacktrace для системного err. Необходимо отслеживать журнал ошибок приложений и открывать проблему Jira для каждого необработанного исключения, которое на самом деле является ошибкой приложения. Программист должен исправить ошибку где-то в файле инициализации.


Рамка коллекций Google предлагает хороший и элегантный способ достижения нулевой проверки.

В библиотечном классе есть метод:

static <T> T checkNotNull(T e) {
   if (e == null) {
      throw new NullPointerException();
   }
   return e;
}

И использование (с import static ):

...
void foo(int a, Person p) {
   if (checkNotNull(p).getAge() > a) {
      ...
   }
   else {
      ...
   }
}
...

Или в вашем примере:

checkNotNull(someobject).doCalc();

В зависимости от того, какие объекты вы проверяете, вы можете использовать некоторые из классов в сообществах apache, таких как: apache commons lang и коллекции коллекций apache

Пример:

String foo;
...
if( StringUtils.isBlank( foo ) ) {
   ///do something
}

или (в зависимости от того, что вам нужно проверить):

String foo;
...
if( StringUtils.isEmpty( foo ) ) {
   ///do something
}

Класс StringUtils является лишь одним из многих; есть довольно много хороших классов в достояниях, которые делают нулевую безопасную манипуляцию.

Ниже приведен пример того, как вы можете использовать null vallidation в JAVA, когда вы включаете библиотеку apache (commons-lang-2.4.jar)

public DOCUMENT read(String xml, ValidationEventHandler validationEventHandler) {
    Validate.notNull(validationEventHandler,"ValidationHandler not Injected");
    return read(new StringReader(xml), true, validationEventHandler);
}

И если вы используете Spring, Spring также имеет одинаковую функциональность в своем пакете, см. Библиотеку (spring-2.4.6.jar)

Пример использования этого static classf из Spring (org.springframework.util.Assert)

Assert.notNull(validationEventHandler,"ValidationHandler not Injected");

В конечном счете, единственный способ полностью решить эту проблему - использовать другой язык программирования:

  • В Objective-C вы можете сделать эквивалент вызова метода nil, и абсолютно ничего не произойдет. Это делает ненужными проверки большинства нулей, но это может сделать ошибки намного сложнее диагностировать.
  • В Nice , языке Java, существует две версии всех типов: потенциально-нулевая версия и непустая версия. Вы можете использовать методы только для непустых типов. Потенциально-нулевые типы могут быть преобразованы в непустые типы через явную проверку для null. Это значительно облегчает понимание того, где нужны нулевые проверки, а где нет.

Я пробовал, NullObjectPatternно для меня не всегда лучший способ. Иногда бывает, когда «никакое действие» не подходит.

NullPointerExceptionэто исключение Runtime, которое означает, что это ошибки разработчиков и с достаточным опытом он сообщает вам, где именно ошибка.

Теперь ответ:

Постарайтесь, чтобы все ваши атрибуты и его аксессоры были как можно более закрытыми или вообще не раскрывали их клиентам. Разумеется, вы можете иметь значения аргументов в конструкторе, но, уменьшая область действия, которую вы не позволяете классу клиента передавать недопустимое значение. Если вам нужно изменить значения, вы всегда можете создать новое object. Вы проверяете значения в конструкторе только один раз, а в остальных методах вы можете быть почти уверены, что значения не равны нулю.

Конечно, опыт - лучший способ понять и применить это предложение.

Байт!







null