Избегать! = Нулевые заявления

3428

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

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

Например:

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

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

Обратите внимание, что принятый ответ может быть устаревшим, см. https://stackoverflow.com/questions/271526/avoiding-null-statements для более позднего подхода.

  • 3
    @Tom Хотин: Там, где об этом говорят, по крайней мере: tech.puredanger.com/java7/#null Может быть, они решили не реализовывать это в конце концов. Я не уверен...
  • 2
    @ Шервин О многих вещах говорили. Я думаю, что предложения были в три цифры. Но я не думаю, что это когда-либо было предназначено, чтобы поднять это.
Показать ещё 32 комментария
Теги:
object
nullpointerexception
null

59 ответов

2422
Лучший ответ

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

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

  • Где null - действительный ответ в терминах контракта; и

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

(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);
        }
    }
}
  • 609
    Я не согласен с вашими заявлениями о действии DO_NOTHING. Если метод find action не может найти действие, то возвращение null является правильным решением. Вы «нашли» в своем коде действие, которое на самом деле не найдено, что нарушает принцип метода, чтобы найти полезное действие.
  • 258
    Я согласен с тем, что null используется в Java слишком часто, особенно в списках. Так много apis было бы лучше, если бы они возвращали пустой список / массив / коллекцию вместо null. Много раз, ноль используется, где вместо этого должно быть выброшено исключение. Исключение должно быть выдано, если парсер не может разобрать.
Показать ещё 50 комментариев
502

Если вы используете (или планируете использовать) 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 аннотации.

  • 114
    @NotNull , @Nullable и другие аннотации недействительности являются частью JSR 305 . Вы также можете использовать их для обнаружения потенциальных проблем с такими инструментами, как FindBugs .
  • 30
    Я нахожу странным, что интерфейсы @NotNull & @Nullable живут в пакете com.sun.istack.internal . (Думаю, я связываю com.sun с предупреждениями об использовании проприетарного API.)
Показать ещё 14 комментариев
272

Если значения 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 && ...".

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

  • 94
    Какой смысл в создании IllegalArgumentException? Я думаю, что NullPointerException будет более понятным, и это также будет сгенерировано, если вы сами не выполняете проверку на ноль. Я бы либо использовал assert, либо вообще ничего.
  • 23
    Маловероятно, что любое другое значение, кроме нуля, является приемлемым. Вы можете иметь IllegalArgumentException, OutOfRageException и т. Д. И т. Д. Иногда это имеет смысл. В других случаях вы в конечном итоге создаете много классов исключений, которые не добавляют никакого значения, тогда вы просто используете IllegalArgumentException. Не имеет смысла иметь одно исключение для нулевого ввода и другое для всего остального.
Показать ещё 10 комментариев
206

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

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

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

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


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


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

  • 19
    Я думаю, что это неправильно. Должен быть способ указать, что данная переменная ВСЕГДА не равна нулю.
  • 5
    Обновление: предложение не будет делать Java7. Смотрите blogs.sun.com/darcy/entry/project_coin_final_five .
Показать ещё 13 комментариев
170

Если неопределенные значения не разрешены:

Вы можете настроить свою среду IDE, чтобы предупредить вас о потенциальной нулевой разыменовании. Например, в Eclipse см. настройки> Java> Компилятор> Ошибки/Предупреждения/Нулевой анализ.

Если разрешены неопределенные значения:

Если вы хотите определить новый API, где неопределенные значения имеют смысл, используйте шаблон Option (может быть знаком с функциональными языками). Он имеет следующие преимущества:

  • В API явно указано, существует или нет вход или выход.
  • Компилятор заставляет вас обрабатывать "undefined" случай.
  • Вариант - монада, поэтому нет необходимости в проверке верных нулей, просто используйте map/foreach/getOrElse или аналогичный комбинатор, чтобы безопасно использовать значение (пример).

Java 8 имеет встроенный Optional класс (рекомендуется); для более ранних версий существуют альтернативы библиотеки, например, Optional Guava Option или FunctionalJava. Но, как и многие функциональные шаблоны, использование Option в Java (даже 8) приводит к довольно некоторому шаблону, который вы можете уменьшить, используя менее подробный язык JVM, например Scala или Xtend.

Если вам нужно иметь дело с API, который может возвращать значения NULL, вы не можете многое сделать на Java. У Xtend и Groovy есть оператор Элвиса ?: И нульбезопасный оператор разыменования ?. , но обратите внимание, что это возвращает null в случае нулевой ссылки, поэтому он просто "отменяет" правильную обработку нулевого значения.

  • 21
    В самом деле, шаблон Option является потрясающим. Некоторые Java-эквиваленты существуют. Guava содержит ограниченную версию этого приложения, которая не включает большинство функциональных возможностей. В Хаскеле этот шаблон называется «Возможно».
  • 0
    @Luca Molteni: Вы абсолютно правы, я уже прокомментировал сообщение с просьбой расширить его. :)
Показать ещё 6 комментариев
155

Только для этой ситуации -

Не проверять, имеет ли переменная значение null перед вызовом метода equals (пример сравнения строк ниже):

if ( foo.equals("bar") ) {
 // ...
}

приведет к NullPointerException если foo не существует.

Вы можете избежать этого, если сравнить свою String следующим образом:

if ( "bar".equals(foo) ) {
 // ...
}
  • 39
    Я согласен - только в такой ситуации. Я не могу вынести программистов, которые подняли это на следующий ненужный уровень и пишут if (null! = MyVar) ... просто выглядит уродливо для меня и не имеет смысла!
  • 19
    Это частный пример, возможно, наиболее часто используемый, из общей хорошей практики: если вы знаете это, всегда делайте <object that you know that is not null>.equals(<object that might be null>); , Он работает для других методов, отличных от equals если вы знаете контракт, и эти методы могут обрабатывать null параметры.
Показать ещё 5 комментариев
143

В 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() позволяет вам предоставить резервную копию для отсутствующих значений.

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

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

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

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

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

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

  • 11
    гуавы Google имеет дополнительный implimention для Java 6+.
  • 12
    Очень важно подчеркнуть, что использование Optional только с ifPresent () не добавляет много значения выше обычной проверки нуля. Основное значение в том, что это монада, которую можно использовать в цепочках функций map / flapMap, которая дает результаты, аналогичные оператору Elvis в Groovy, упомянутом в другом месте. Тем не менее, даже без этого использования, я нахожу синтаксис orElse / orElseThrow также очень полезным.
Показать ещё 4 комментария
118

В зависимости от того, какие объекты вы проверяете, вы можете использовать некоторые из классов в общих долях 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)

Пример использования этого статического класса f из spring (org.springframework.util.Assert)

Assert.notNull(validationEventHandler,"ValidationHandler not Injected");
  • 5
    Также вы можете использовать более общую версию от Apache Commons, весьма полезную в начале методов для проверки параметров, которые я нахожу. Validate.notNull (объект, "объект не должен быть нулевым"); commons.apache.org/lang/apidocs/org/apache/commons/lang/...
  • 0
    @monojohnny Validate использует утверждения Assert в ?. Я спрашиваю об этом, потому что Assert может быть активирован / деактивирован на JVM, и он предлагает не использовать в производстве.
Показать ещё 1 комментарий
87
  • Если вы считаете, что объект не должен быть нулевым (или это ошибка), используйте assert.
  • Если ваш метод не принимает нулевые параметры, скажите это в javadoc и используйте assert.

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

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

85

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

  • 2
    лучше использовать утверждения, то есть Contract.notNull (abc, «abc должен быть ненулевым, не удалось загрузить во время xyz?»); - это более компактный способ, чем выполнение if (abc! = null) {throw new RuntimeException ...}
70

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

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

  • 17
    Проблема заключается в том, что обычно вы теряете контекст, так как исключение NullPointerException не указывает, какая переменная была нулевой, и у вас может быть несколько «.» - операций в строке. Использование "if (foo == null) throw new RuntimeException (" foo == null ")" позволяет вам явно указать ЧТО было не так, давая вашей трассировке стека гораздо большую ценность для тех, кто должен это исправить.
  • 1
    С Андерсеном - я бы хотел, чтобы система исключений Java включала в себя имя переменной, над которой работали, чтобы NullPointerExceptions указывал не только на строку, в которой произошло исключение, но также и имя переменной. Это должно работать просто отлично в необфокусированном программном обеспечении.
Показать ещё 3 комментария
69

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

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

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

  • 2
    Но тогда вы должны предположить, что equals (это может быть любой метод) будет правильно обрабатывать нуль. На самом деле все, что это делает - это передает ответственность кому-то другому (или другому методу).
  • 4
    @Supericy В основном да, но equals (или любой другой метод) должен все равно проверять на null . Или прямо заявите, что это не так.
68

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

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

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

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

становится

Parent(Child child) {
   this.child = Objects.requireNonNull(child, "child");
}
  • 8
    На самом деле, ваш пример представляет собой раздувание кода: первая строка излишня, потому что NPE будет брошен во вторую строку. ;-)
  • 1
    Правда. Лучшим примером было бы, если вторая строка была doCalc(someObject) .
Показать ещё 5 комментариев
66

Структура коллекций 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();
  • 71
    ммм, в чем разница? p.getAge () выдаст тот же NPE с меньшими издержками и более четкой трассировкой стека. Что мне не хватает?
  • 15
    Лучше добавить исключение IllegalArgumentException ("e == null") в вашем примере, поскольку оно четко указывает на то, что это исключение, предназначенное для программиста (вместе с достаточным количеством информации, позволяющей сопровождающему идентифицировать проблему). Исключения NullPointerException должны быть зарезервированы для JVM, так как это ясно указывает на то, что это было непреднамеренно (и обычно это происходит где-то, что трудно идентифицировать)
Показать ещё 5 комментариев
60

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

  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 null safe API (если он будет выпущен еще через 10 лет), но NullPointerException является подклассом Exception. Таким образом, это форма Throwable которая указывает условия, которые разумное приложение может захотеть поймать (javadoc)! Чтобы использовать первое преимущество привилегий и отдельный код обработки ошибок из "обычного" кода (по словам создателей Java), уместно, как и я, поймать NullPointerException.

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

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

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

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

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

    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 (для определения и использования вашего любимого регистратора или другого механизма уведомления). Если не задано, ThreadGroup # uncaughtException будет печатать stacktrace для системного err. Необходимо отслеживать журнал ошибок приложений и открывать проблему Jira для каждого необработанного исключения, которое на самом деле является ошибкой приложения. Программист должен исправить ошибку где-то в файле инициализации.

  • 0
    Тот факт, что он предназначен для обозначения «нет данных», не означает, что его следует использовать. Языковая реализация null отстой.
  • 6
    Поймать NullPointerException и вернуть null ужасно для отладки. В конце концов, вы все равно получите NPE, и очень трудно понять, что изначально было нулевым.
Показать ещё 16 комментариев
44

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

  • В Objective-C вы можете сделать эквивалент вызова метода на nil, и абсолютно ничего не произойдет. Это делает ненужные проверки, но может сделать ошибки намного сложнее для диагностики.
  • В Nice, языке Java, существует две версии всех типов: потенциально-нулевая версия и не- null версия. Вы можете использовать методы только для непустых типов. Потенциально-нулевые типы могут быть преобразованы в непустые типы через явную проверку для null. Это значительно облегчает понимание необходимости нулевых проверок и того, где они не являются.
  • 0
    Вау ... Самый правильный ответ и его опровергают, где справедливость? В Java null всегда является допустимым значением. Это следствие «Все есть объект» - «Ноль есть все» (конечно, мы игнорируем примитивы здесь, но вы понимаете). Лично я одобряю подход, принятый Nice, хотя мы могли бы сделать так, чтобы методы могли вызываться для типов, допускающих обнуляемость, и повышать NPE до проверенных исключений. Это должно быть сделано с помощью переключателя компилятора, так как это сломает весь существующий код :(
  • 3
    Я не знаком с Nice, но Kotlin реализует ту же идею: встроенные типы Nullable и NULL встроены в систему типов языка. Намного более сжатый, чем шаблон Optionals или NULL.
33

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

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

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

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



    .....
}
  • 2
    Мм, почему это? Пожалуйста, не чувствуйте никакой защиты, я просто хотел бы узнать больше о Java :)
  • 9
    @Mudu Как правило, я предпочитаю, чтобы выражение в выражении if было более «положительным», чем «отрицательным». Так что, если я видел, if (!something) { x(); } else { y(); } Что- if (!something) { x(); } else { y(); } Я был бы склонен к рефакторингу, как if (something) { y(); } else { x(); } (хотя можно утверждать, что != null - более позитивный вариант ...). Но что еще более важно, важная часть кода не обернута внутри {} и у вас на один уровень меньше отступов для большей части метода. Я не знаю, было ли это рассуждением fastcodejava, но это было бы моим.
Показать ещё 1 комментарий
32

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

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

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

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

Как я решаю эту проблему:

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

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

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

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

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

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

void validate() throws ValidationException;

Сообщение будет содержать следующий текст, если, например, "планы" имеют значение null:

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

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

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

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

  • 1
    Абсолютно. Приложения, которые просто выдают ошибку и сбой, имеют более высокое качество, потому что нет никаких сомнений, когда они не работают. Приложения, которые в лучшем случае проглатывают ошибки, изящно деградируют, но обычно не работают так, что их трудно заметить и не исправить. И когда проблема замечена, их гораздо сложнее отладить.
31

Задавая вопрос о том, что вы можете быть заинтересованы в стратегиях обработки ошибок. Архитектор вашей команды должен решить, как работать с ошибками. Существует несколько способов сделать это:

  • позволяют Исключениям пульсировать через - поймать их в "основном цикле" или в какой-то другой управляющей процедуре.

    • проверьте условия ошибок и соответствующим образом обработайте их

Конечно, посмотрите также на Aspect Oriented Programming - у них есть четкие способы вставить if( o == null ) handleNull() в ваш байт-код.

29

Просто не используйте значение 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, вам нужно как-то понять.

  • 0
    почему это будет опущено? по моему опыту, это намного превосходит другие подходы, хотелось бы знать, почему нет
  • 0
    Я согласен, что этот подход предотвращает проблемы, связанные с нулями, вместо того, чтобы их исправлять, повсюду проверяя нулями проверки кода.
Показать ещё 4 комментария
29

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

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

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

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

Optional<Integer> possible = Optional.of(5);
possible.isPresent(); // returns true
possible.get(); // returns 5
  • 0
    @CodyGuldner Правильно, Коди. Я предоставил соответствующую цитату из ссылки, чтобы дать больше контекста.
19

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

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

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

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

ОТКЛЮЧЕНИЕ К ОПЦИИ <T>

Рассмотрим способ получения ссылки службы из factory. Вместо того, чтобы возвращать служебную ссылку, оберните ее опцией. Это позволяет пользователю 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... Действительно?.

19

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

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

  • 0
    Майкл Фезерс написал короткий и интересный текст о подходах, подобных тому, который вы упомянули: manuelp.newsblur.com/site/424
18

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

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

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

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

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

Byte!

15

Вероятно, лучшей альтернативой Java 8 или новее является использование класса Optional.

Optional stringToUse = Optional.of("optional is there");
stringToUse.ifPresent(System.out::println);

Это особенно удобно для длинных цепочек возможных нулевых значений. Пример:

Optional<Integer> i = Optional.ofNullable(wsObject.getFoo())
    .map(f -> f.getBar())
    .map(b -> b.getBaz())
    .map(b -> b.getInt());

Пример того, как выбрасывать исключение в null:

Optional optionalCarNull = Optional.ofNullable(someNull);
optionalCarNull.orElseThrow(IllegalStateException::new);

Java 7 представила метод Objects.requireNonNull, который может быть полезен, когда что-то нужно проверить для непустоты. Пример:

String lowerVal = Objects.requireNonNull(someVar, "input cannot be null or empty").toLowerCase();
14

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

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

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

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

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

  • 0
    Решение с "hasBackground ()" имеет один недостаток - оно не поточно-ориентированное. Если вам нужно вызвать два метода вместо одного, вам нужно синхронизировать всю последовательность в многопоточной среде.
  • 0
    @pkalinow Вы сделали надуманный пример только для того, чтобы указать, что у этого решения есть недостаток. Если код не предназначен для запуска в многопоточном приложении, то недостатка нет. Я мог бы поместить в вас, вероятно, 90% вашего кода, который не является потокобезопасным. Мы не говорим здесь об этом аспекте кода, мы говорим о шаблоне проектирования. А многопоточность - это отдельная тема.
Показать ещё 2 комментария
14

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

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

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

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;

   // ...
}
  • 0
    javax по определению не является «ядром Java».
13

Это самая распространенная ошибка для большинства разработчиков.

У нас есть несколько способов справиться с этим.

Подход 1:

org.apache.commons.lang.Validate //using apache framework

notNull (объект объекта, сообщение String)

Подход 2:

if(someObject!=null){ // simply checking against null
}

Подход 3:

@isNull @Nullable  // using annotation based validation

Подход 4:

// by writing static method and calling it across whereever we needed to check the validation

static <T> T isNull(someObject e){  
   if(e == null){
      throw new NullPointerException();
   }
   return e;
}
  • 0
    Объявление. 4. Это не очень полезно - когда вы проверяете, равен ли указатель нулю, вы, вероятно, захотите вызвать метод для него. Вызов метода с нулевым значением дает вам то же поведение - NullPointerException.
13
  • Не инициализировать переменные до нуля.
  • Если (1) невозможно, инициализируйте все коллекции и массивы пустым коллекциям/массивам.

Выполняйте это в своем собственном коде, и вы можете избежать!= нулевые проверки.

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

// Bad
ArrayList<String> lemmings;
String[] names;

void checkLemmings() {
    if (lemmings != null) for(lemming: lemmings) {
        // do something
    }
}



// Good
ArrayList<String> lemmings = new ArrayList<String>();
String[] names = {};

void checkLemmings() {
    for(lemming: lemmings) {
        // do something
    }
}

В этом есть крошечные накладные расходы, но это стоит того, чтобы сделать более чистый код и меньше NullPointerExceptions.

  • 0
    stackoverflow.com/questions/1386275/...
  • 3
    +1 С этим я согласен. Вы никогда не должны возвращать половину инициализированных объектов. Код, связанный с Jaxb, и код bean-кода notiroius для этого. Это плохая практика. Все коллекции должны быть инициализированы, и все объекты должны существовать без (в идеале) нулевых ссылок. Рассмотрим объект, в котором есть коллекция. Проверка того, что объект не является нулевым, что коллекция не является нулевым и что коллекция не содержит нулевых объектов, является необоснованной и глупой.
9

Java 8 представила новый класс Необязательный в пакете java.util.

Преимущества Java 8 Дополнительно:

1.) Нулевые проверки не требуются.
2.) Во время выполнения не должно быть больше NullPointerException.
3.) Мы можем разработать чистые и опрятные API.

Необязательный - контейнерный объект, который может содержать или не содержать ненулевое значение. Если значение присутствует, isPresent() вернет true и get() вернет значение.

Для получения дополнительной информации см. Здесь oracle docs: - https://docs.oracle.com/javase/8/docs/api/java/util/Optional.html

8

Вы можете использовать FindBugs. У них также есть Eclipse плагин), который поможет вам найти дубликаты нулевых проверок (между прочим), но имейте в виду, что иногда вам следует выберите защитное программирование. Существует также Контракты для Java, которые могут быть полезны.

7

Так как Java 7 существует класс java.util.Objects.

Но так как Java 8, вы можете использовать методы Objects.isNull(var) и Objects.nonNull(var) класса Objects для проверки нулевого указателя.

Например,

String var1 = null;
Date var2 = null;
Long var3 = null;

if(Objects.isNull(var1) && Objects.isNull(var2) && Objects.isNull(var3))
    System.out.println("All Null");
else if (Objects.nonNull(var1) && Objects.nonNull(var2) && Objects.nonNull(var3))
    System.out.println("All Not Null");
7

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

  • Избегайте ленивой инициализации переменных-членов как можно больше. Инициализация переменных в самой декларации. Это будет обрабатывать NullPointerExceptions.

  • Определите изменчивость переменных-членов в начале цикла. Используйте языковые конструкции, такие как final.

  • Если вы знаете, что дополнения для метода не будут изменены, объявите их как final.

  • Максимально ограничьте мутацию данных. Некоторые переменные могут быть созданы в конструкторе и никогда не могут быть изменены. Удалить общедоступные методы настройки, если они действительно не требуются.

    например. Предположим, что один класс в вашем приложении (A.java) поддерживает коллекцию типа HashMap. Не предоставляйте метод public getter в A.java и позволяйте B.java напрямую добавлять элемент в Map. Вместо этого предоставим API в A.java, который добавит элемент в коллекцию.

    // Avoid
    a.getMap().put(key,value)
    
    //recommended
    
    public void addElement(Object key, Object value){
           // Have null checks for both key and value here : single place
           map.put(key,value);
    }
    
  • И, наконец, эффективно используйте try{} catch{} finally{} блоки в правильных местах.

  • 0
    Этому определенно нужно больше голосов
6

В целом, чтобы избежать заявления

if (object != null) {
    ....
}
  1. с помощью java 7 вы можете использовать методы Objects:

    Objects.isNull (объект)

    Objects.nonNull (объект)

    Objects.requireNonNull (объект)

    Objects.equals(object1, object2)

  2. так как java 8 можно использовать Необязательный класс (когда использовать)

object.ifPresent(obj ->...); java 8

object.ifPresentOrElse(obj ->...,() ->...); java 9

  1. полагайтесь на контракт метода (JSR 305) и используйте " Найти ошибки". Отметьте свой код аннотациями @javax.annotation.Nullable и @javax.annotation.Nonnnul. Также доступны предварительные условия.

    Preconditions.checkNotNull (объект);

  2. В особых случаях (например, для строк и коллекций) вы можете использовать утилиты apache-commons (или Google guava):

public static boolean isEmpty (CharSequence cs)//apache CollectionUtils

public static boolean isEmpty (Collection coll)//apache StringUtils

public static boolean isEmpty (Карта карты)//apache MapUtils

public static boolean isNullOrEmpty (строка @Nullable String)//Строки Guava

  1. Когда вам нужно назначить значение по умолчанию, когда null использует apache commons lang

public static Object defaultIfNull (объект Object, Object defaultValue)

  • 0
    объяснить очень хорошо
6

Еще одна альтернатива:

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

public static <T> boolean isNull(T argument) {
    return (argument == null);
}

Теперь вы можете написать

if (!isNull(someobject)) {
    someobject.doCalc();
}

который является IMO лучшим способом выражения != null.

  • 7
    Если вы постоянно отрицаете возвращаемое значение, не лучше ли просто написать функцию isNotNull ? Разве это не указывает на ваши намерения?
  • 0
    @ TMN: вы правы, в идеале, я бы хотел иметь метод isNull и isNotNull .
Показать ещё 2 комментария
6

Где бы вы ни проходили массив или вектор, инициализируйте их пустым, а не null. - Таким образом, вы можете избежать большого количества проверок на нуль, и все это хорошо:)

public class NonNullThing {

   Vector vectorField = new Vector();

   int[] arrayField = new int[0];

   public NonNullThing() {

      // etc

   }

}
5

Я считаю, что условия Guava Precditions очень полезны в этом случае. Мне не нравится оставлять nulls в исключении null-указателя, поскольку единственный способ понять NPE - это найти номер строки. Номера строк в версии производства и версии разработки могут быть разными.

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

Например,

Preconditions.checkNotNull(paramVal, "Method foo received null paramVal");
4

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

  1. public static boolean isNull(Object obj)

    Возвращает true, если предоставленная ссылка равна null, иначе возвращает false.

    Поскольку Java 1.8

  2. public static boolean nonNull(Object obj)

    Возвращает true, если предоставленная ссылка не имеет значения null, иначе возвращает false.

    Поскольку Java 1.8

  3. public static <T> T requireNonNullElse​(T obj, T defaultObj)

    Возвращает первый аргумент, если он не равен null и в противном случае возвращает ненулевой второй аргумент.

    Начиная с Java 9

  4. public static <T> T requireNonNullElseGet​(T obj, Supplier<? extends T> supplier)

    Возвращает первый аргумент, если он не является нулевым и в противном случае возвращает ненулевое значение поставщика.get().

    Начиная с Java 9

  5. public static <T> T requireNonNull​(T obj, Supplier<String> messageSupplier)

    Проверяет, что указанная ссылка объекта не является нулевой и в противном случае выбрасывает исключение NullPointerException.

    Поскольку Java 1.8

Более подробную информацию о вышеуказанных функциях можно найти здесь.

  • 0
    Вы можете видеть, что есть много ответов со многими ответами, что особенного в вашем ответе?
  • 0
    Я просто хотел добавить еще несколько функций, доступных в Java 9 .
Показать ещё 2 комментария
4

В Java 8 вы можете использовать тип T для параметра local-variable/field/method-argument/method-return-type, если он никогда не назначал null (и не проверяет на null), или введите Optional<T> если это может быть null. Затем используйте метод map для обработки T -> и метод flatMap для обработки T -> Optional<R>:

class SomeService {
    @Inject
    private CompanyDao companyDao;

    // return Optional<String>
    public Optional<String> selectCeoCityByCompanyId0(int companyId) {
        return companyDao.selectById(companyId)
                .map(Company::getCeo)
                .flatMap(Person::getHomeAddress)
                .flatMap(Address::getCity);
    }

    // return String + default value
    public String selectCeoCityByCompanyId1(int companyId) {
        return companyDao.selectById(companyId)
                .map(Company::getCeo)
                .flatMap(Person::getHomeAddress)
                .flatMap(Address::getCity)
                .orElse("UNKNOWN");
    }

    // return String + exception
    public String selectCeoCityByCompanyId2(int companyId) throws NoSuchElementException {
        return companyDao.selectById(companyId)
                .map(Company::getCeo)
                .flatMap(Person::getHomeAddress)
                .flatMap(Address::getCity)
                .orElseThrow(NoSuchElementException::new);
    }
}

interface CompanyDao {
    // real situation: no company for such id -> use Optional<Company> 
    Optional<Company> selectById(int id);
}

class Company {
    // company always has ceo -> use Person 
    Person ceo;
    public Person getCeo() {return ceo;}
}

class Person {
    // person always has name -> use String
    String firstName;
    // person can be without address -> use Optional<Address>
    Optional<Address> homeAddress = Optional.empty();

    public String getFirstName() {return firstName;}   
    public Optional<Address> getHomeAddress() {return homeAddress;}
}

class Address {
    //  address always contains country -> use String
    String country;
    //  city field is optional -> use Optional<String>
    Optional<String> city = Optional.empty();

    String getCountry() {return country;}    
    Optional<String> getCity() {return city;}
}
4

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

Предположим, что M1 (Object test) - это метод, а M2 - метод, в котором мы применяем аспект перед вызовом метода M2(Object test2). Если test2 != null, тогда вызовите M1, иначе выполните другую вещь. Он работает для всех методов, с которыми вы хотите применить аспект. Если вы хотите применить аспект для поля экземпляра и конструктора, вы можете использовать AspectJ. Spring также может быть лучшим выбором для аспекта метода.

  • 0
    Вы предлагаете перехватить каждый метод всего приложения?
3

В Java 8 теперь есть необязательный класс, который обертывает рассматриваемый объект, и если значение присутствует, isPresent() вернет true и get() вернет значение.

http://www.oracle.com/technetwork/articles/java/java8-optional-2175753.html

3

Вы также можете использовать Checker Framework (с JDK 7 и далее) для статической проверки нулевых значений. Это может решить множество проблем, но требует запуска дополнительного инструмента, который в настоящее время работает только с OpenJDK AFAIK. https://checkerframework.org/

2

Если вы используете java7 или более позднюю версию для isNull(yourObject) от java.util.Objects.

Пример: -

String myObject = null;

Objects.isNull(myObject); //will return true
  • 0
    Это не сильно отличается от myObject == null и было введено в Java8 для Predicates в лямбда-функции.
  • 0
    Objects.isNull () доступен с Java8 (не Java7)
Показать ещё 1 комментарий
2

Чтобы избежать ненужного null-checks, просто указать:

You need to know which variables can be null, and which cannot, and you need to be confident about which category a given variable fall into.

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

Нет быстрых и простых ответов на это, но вот несколько указателей:

  • Очистить код. Самое главное, чтобы иметь возможность рассуждать о поведении части кода, заключается в том, что он написан в понятном для понимания вопросе. Назовите свои переменные на основе того, что они представляют, назовите свои методы после того, что они делают, примените Single responsibility principle (S in SOLID: http://en.wikipedia.org/wiki/SOLID_(object-oriented_design), это означает, что каждый кусок кода должен иметь отдельную ответственность, а делать это и ничего больше). После того, как ваш код чист, гораздо проще рассуждать об этом, а также на нескольких уровнях/слоях кода. С грязным кодом, пытаясь понять, что метод может заставить вас забыть, почему вы читаете этот метод в первую очередь. (Совет: прочитайте "Чистый код" Роберта К. Мартина)

  • Избегайте возвращать значения null. Если значение null будет поддерживать вашу программу в правильном порядке, добавьте вместо нее exception (обязательно добавьте соответствующую обработку ошибок). Случаи, когда возвращение значения null может быть приемлемым, например, пытается извлечь объект из базы данных. В этих случаях напишите код, который обрабатывает значения null, и запомните за ухом, что у нас есть что-то, что может вернуться null. Handle возвратил значения null как можно ближе к вызывающему методу, возвращающему null, насколько это возможно (не просто слепо передавайте его обратно в цепочку вызовов.)

  • Никогда НИКОГДА не передавайте явные значения null в качестве параметров (по крайней мере, не для всех классов). Если вы когда-либо находились в положении, когда передача null -параметра является единственным вариантом, создание нового метода, который не имеет этого параметра, - это путь.

  • Подтвердите свой ввод! Определите "входные точки" для вашего приложения. Они могут все: от веб-сервисов, REST-сервисов, удаленных классов EJB, контроллеров и т.д. Для каждого метода в этих точках входа задайте себе вопрос: "Будет ли этот метод правильно выполняться, если этот параметр равен нулю?" Если ответ отрицательный, добавьте Validate.notNull(someParam, "Can't function when someParam is null!");. Это вызовет IllegalArgumentException, если нужный параметр отсутствует. Хорошая вещь об этом типе проверки в точках входа заключается в том, что вы можете легко предположить в исполняемом коде из точки входа, что эта переменная никогда не будет равна нулю! Кроме того, если это не удается, находясь на начальной точке, отладка выполняется намного проще, чем если бы вы только получили NullPointerException в глубине вашего кода, так как такой отказ может означать только одно: клиент didn Вы отправляете всю необходимую информацию. В большинстве случаев вы хотите проверить все входные параметры, если вы окажетесь в положении, когда вам нужно разрешить много значений null, это может быть признаком плохо разработанного интерфейса, который нуждается в рефакторинге/добавлении в набор потребности клиентов.

  • При работе с Collection s верните пустой, а не пустой!

  • При работе с базой данных используйте not null -constraints. Таким образом, вы узнаете, что значение, считанное из базы данных, не может быть нулевым, и вам не нужно проверять его.

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

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

Вам по-прежнему необходимо проверить нуль, но он может быть сведен к минимуму (т.е. ситуация, когда вы знаете, что можете получить нулевое значение, а не везде, чтобы быть уверенным.) Когда дело доходит до null-check, я фактически предпочитаю использовать тернарный оператор (но используйте с осторожностью, когда вы начинаете их вложенность, они становятся очень запутанными.)

public String nullSafeToString(final Object o) {
    return o != null ? o.toString() : "null";
}
2

Прежде всего, мы не можем удалить все нулевые условия. Мы можем уменьшить их, используя аннотации @NotNull и @Nullable (, как уже упоминалось). Но это нужно подкреплять некоторыми рамками. Здесь OVal может помочь.

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

Я предполагаю, что OVal внутренне использует AspectJ для проверки предварительных условий.

@Guarded
public class BusinessObject
{
  public BusinessObject(@NotNull String name)
  {
    this.name = name;
  }

  ...
}

Например,

// Throws a ConstraintsViolatedException because parameter name is null
BusinessObject bo = new BusinessObject(null);
2

Хорошо, теперь мне это технически ответили миллион раз, но я должен сказать это, потому что это бесконечное обсуждение с Java-программистами.

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

Я говорю это, потому что у меня есть многолетний опыт программирования на С++, и мы этого не делаем. Другими словами, вам не нужно. И обратите внимание, что в Java, если вы нажмете висячий указатель, вы получите нормальное исключение; в С++ это исключение обычно не захватывается и завершает работу программы.

Не хотите это делать? Затем следуйте простым правилам ala C/С++.

Не создавайте вещи так легко, подумайте, что каждое "новое" может вызвать у вас массу неприятностей и ПОСЛЕДОВАТЬ эти простые правила.

Класс должен получить доступ к памяти только тремя способами →

  • Он может "иметь" члены класса, и они будут следовать этим правилам:

    • Все члены "HAS" создаются "new" в конструкторе.
    • Вы закроете/выделите в деструкторе или эквивалентном close() функции в Java для этого же класса и в НЕТ других.

Это означает, что вам нужно иметь в виду (как и Java), кто является владельцем или родителем каждого ресурса и уважает это право собственности. Объект удаляется только классом, который его создал. Также →

  1. Некоторые участники будут "ИСПОЛЬЗОВАНЫ", но не являются собственными или "ИМЕЮТ". Это "OWN" в другом классе и передано в качестве аргументов конструктору. Поскольку они принадлежат другому классу, мы НИКОГДА не удалим или не закроем его, только родитель может.

  2. Метод в классе также может создавать локальные объекты для внутреннего использования, которые НИКОГДА не покидают сторону класса, или они должны были быть нормальными объектами "есть".

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

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

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

  • 1
    Договорились, хотя и только концептуально. Да, нужно иметь план. Но тогда вам нужны программисты, которые МОГУТ ПЛАНИТЬ ПЛАНЫ и способны логически мыслить, разрабатывать и поддерживать согласованные шаблоны. А потом есть работодатели, чей основной упор делается на деньги и заработную плату ;-). А затем начните знакомиться со спецификацией JPA, чтобы получить представление о том, что представляет собой согласованный шаблон / план и что требуется для его разработки и / или документирования.
  • 3
    Этот ответ актуален для C ++, но не для языка сборки мусора, такого как Java.
Показать ещё 7 комментариев
1

Котлин с нулевой безопасностью - изящная альтернатива, но это означает большее изменение.

1

Можно определить методы использования, которые почти полностью обрабатывают вложенные нулевые проверки с помощью Java 8 lambdas.

void example() {
    Entry entry = new Entry();
    // This is the same as H-MANs solution 
    Person person = getNullsafe(entry, e -> e.getPerson());    
    // Get object in several steps
    String givenName = getNullsafe(entry, e -> e.getPerson(), p -> p.getName(), n -> n.getGivenName());
    // Call void methods
    doNullsafe(entry, e -> e.getPerson(), p -> p.getName(), n -> n.nameIt());        
}

/** Return result of call to f1 with o1 if it is non-null, otherwise return null. */
public static <R, T1> R getNullsafe(T1 o1, Function<T1, R> f1) {
    if (o1 != null) return f1.apply(o1);
    return null; 
}

public static <R, T0, T1> R getNullsafe(T0 o0, Function<T0, T1> f1, Function<T1, R> f2) {
    return getNullsafe(getNullsafe(o0, f1), f2);
}

public static <R, T0, T1, T2> R getNullsafe(T0 o0, Function<T0, T1> f1, Function<T1, T2> f2, Function<T2, R> f3) {
    return getNullsafe(getNullsafe(o0, f1, f2), f3);
}


/** Call consumer f1 with o1 if it is non-null, otherwise do nothing. */
public static <T1> void doNullsafe(T1 o1, Consumer<T1> f1) {
    if (o1 != null) f1.accept(o1);
}

public static <T0, T1> void doNullsafe(T0 o0, Function<T0, T1> f1, Consumer<T1> f2) {
    doNullsafe(getNullsafe(o0, f1), f2);
}

public static <T0, T1, T2> void doNullsafe(T0 o0, Function<T0, T1> f1, Function<T1, T2> f2, Consumer<T2> f3) {
    doNullsafe(getNullsafe(o0, f1, f2), f3);
}


class Entry {
    Person getPerson() { return null; }
}

class Person {
    Name getName() { return null; }
}

class Name {
    void nameIt() {}
    String getGivenName() { return null; }
}

(Этот ответ был впервые опубликован здесь.)

1

Мы использовали библиотеки Apache (Apache Commons) для этой проблемы.

ObjectUtils.equals(object, null)

или

CollectionUtils.isEmpty(myCollection);

или

StringUtils.isEmpty("string");

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

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

Надеюсь, это поможет.

  • 1
    Мне не нравятся CollectionUtils.isEmpty и StringUtils.isEmpty как они также выполняют нулевую проверку, которая не подразумевается именем метода.
1

Я предпочитаю это

public void simpleFunc(SomeObject someObject){
    someObject = someObject != null ? someObject : new SomeObject(null);
    someObject.doSomething();
}

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

0

С Java 8 вы можете передать поставщику вспомогательный метод, как показано ниже,

if(CommonUtil.resolve(()-> a.b().c()).isPresent()) {

}

Выше заменяет код плиты котла, как показано ниже,

if(a!=null && a.b()!=null && a.b().c()!=null) {

}

//CommonUtil.java

 public static <T> Optional<T> resolve(Supplier<T> resolver) {
        try {
            T result = resolver.get();
            return Optional.ofNullable(result);
        } catch (NullPointerException var2) {
            return Optional.empty();
        }
    }
0

Один из вариантов, который у вас есть

  • Используйте checker framework @RequiresNonNull для методов. например, вы получите это, если вы вызываете метод, аннотированный как таковой, с нулевым аргументом. Он не сработает во время компиляции, даже до запуска вашего кода! поскольку во время выполнения это будет NullPointerException

    @RequiresNonNull(value = { "#1" })
    static void check( Boolean x) {
        if (x) System.out.println("true");
        else System.out.println("false");
    }
    
    public static void main(String[] args) {
    
    
        check(null);
    
    }
    

получает

[ERROR] found   : null
[ERROR] required: @Initialized @NonNull Boolean
[ERROR] -> [Help 1]

Существуют и другие методы, такие как Use Java 8 Optional, Guava Annotations, Null Object pattern и т.д. Не имеет значения до тех пор, пока вы получите свою цель избежать! = Null

0

Образец нулевого объекта может использоваться как решение этой проблемы. Для этого класс someObject должен быть изменен.

public abstract class SomeObject {
   public abstract boolean isNil();
}

public class NullObject extends SomeObject {
   @Override
   public boolean isNil() {
      return true;
   }
}
public class RealObject extends SomeObject {
   @Override
   public boolean isNil() {
      return false;
   }
}

Теперь проверяется,

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

Мы можем использовать

if (!someObject.isNil()) {
   someobject.doCalc();
}

Ссылка: https://www.tutorialspoint.com/design_pattern/null_object_pattern.htm

  • 4
    Вы просто модифицируете чек. Никакой реальной выгоды не получено. Хотя мы прилагаем дополнительные усилия для реализации предложенного шаблона, код все еще не чист.
0

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

Это одна хорошая причина (из многих) использовать Unit Testing.

0

Вот мой подход.

class MyObjectHandler
{
public static final int EXCEPTION = (-3);
public static final int INACCESSIBLE = (-2);

public static int doSomething (MyObject obj, MyObjectParameter [] input)
{
    int returnValue= 0;

    try
    {
        if (obj != null)
        {
            returnValue = obj.doSomething(input);
        }
        else
        {
            returnValue = MyObjectHandler.INACCESSIBLE;
        }
    }
    catch (Exception e)
    {
        e.printStack();
        returnValue = MyObjectHandler.EXCEPTION;
    }
    finally
    {
        return returnValue;
    }
}

..

}

Тогда ваш код будет таким же:

import xx.xx.xx.MyObjectHandler;
import xx.xx.xx.MyObjectParameter;

class Test
{

    public static void main ()
    {

        MyObject obj = null;

        MyObjectHandler.doSomething(obj, null);

    }

    ..

}
0

В классах утилиты вы можете проверить, что параметры не равны нулю.

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

-1

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

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

  • 2
    -1. Это еще хуже. Теперь вместо сбоя, если вы забыли протестировать, ваша программа молча передает неверное значение.
-2

Загрузите Groovy, настройте Groovy, загрузите плагин Groovy Eclipse и измените файл .java на file.groovy, Тогда:

     String u;
     if (u) {
     } //Cast auto to false,
     else {
     }

Так же, как PHP/JavaScript, Затем продолжайте программировать в обычной Java и это Java++.

  • 9
    «Так же, как php / javascript» ~ Это то, что я пытаюсь избежать.
  • 5
    «Избегать«! = Null »операторов в Java» путем установки groovy ... Как это круто!
Показать ещё 3 комментария
-8

Используйте

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

Это не исключает исключение null-указателя

  • 0
    Я думаю, что вы упустили суть вопроса.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню