Подтвердить что ты не робот

Как отслеживать исключение NullPointerException в цепочке геттеров

Если я получаю исключение NullPointerException в вызове типа:

someObject.getSomething().getSomethingElse().
    getAnotherThing().getYetAnotherObject().getValue();

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

Exception in thread "main" java.lang.NullPointerException
at package.SomeClass.someMethod(SomeClass.java:12)

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

Foo ret1 = someObject.getSomething();
Bar ret2 = ret1.getSomethingElse();
Baz ret3 = ret2.getAnotherThing();
Bam ret4 = ret3.getYetAnotherOject();
int ret5 = ret4.getValue();

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

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

Подсказка: я использую eclipse, и я знаю, что такое отладчик, но я не могу понять, как применить его к проблеме.

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

Я согласился с ответом, который научил меня, когда цепочки getters:

  • Если они не могут вернуть null, соедините их так долго, как вам нравится. Нет необходимости проверять!= Null, не нужно беспокоиться о NullPointerExceptions (предупреждаем, что цепочка по-прежнему vialotes закон demeter, но я могу жить с этим)
  • Если они могут возвращать значение null, никогда, никогда не связывайте их и не выполняйте проверку нулевых значений для каждого из них, которые могут возвращать null

Это делает любые полезные советы по фактической отладке бесполезными.

4b9b3361

Ответ 1

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

Ответ 2

NPE - самый бесполезный Exception в Java, период. Кажется, что это всегда лениво реализовано и никогда не сообщает точно, что вызвало его, даже так же просто, как "class x.y.Z is null" очень помогло бы в отладке таких случаев.

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

someObject.getSomething()
          .getSomethingElse()
          .getAnotherThing()
          .getYetAnotherObject()
          .getValue();

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

Ответ 3

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

Таким образом, вам будет легко найти источник вашего NPE.

Я бы предположил, что вы можете сделать что-то подобное в netbeans или eclipse.

EDIT: Здесь объясняется, как добавить исключающую точку в eclipse

Ответ 4

Если вы часто пишете:

a.getB().getC().getD().getE();

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

См. также Закон Деметры, в котором говорится:

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

Следовательно, не должно быть цепочки сообщений, например. a.getB().getC().doSomething(). После этого "закона" есть еще много преимуществ, кроме упрощения отладки NullPointerExceptions.

Ответ 5

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

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

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

Между тем мы можем мечтать о groovy безопасный навигатор

Ответ 6

Ранняя неудача также является опцией.

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

public Foo getSomething()
{
  Foo result;
  ...
  if (result == null) {
    throw new IllegalStateException("Something is missing");
  }
  return result;
}

Ответ 7

Здесь, как найти ошибку, используя Eclipse.

Сначала установите точку останова на строке:

someObject.getSomething().getSomethingElse().
getAnotherThing().getYetAnotherObject().getValue();

Запустите программу в режиме отладки, разрешите отладчику переключиться на свою перспективу при ударе строки.

Теперь выделите "someObject" и нажмите CTRL + SHIFT + я (или щелкните правой кнопкой мыши и скажите "проверить" ).

Нуль? Вы нашли свой NPE. Это не пусто? Затем выделите someObject.getSomething() (включая скобки) и проверьте его. Это нулевое значение? И т.д. Продолжайте движение по цепочке, чтобы выяснить, где происходит ваш NPE, без необходимости менять код.

Ответ 8

Вы можете обратиться к этому вопросу об исключении!= null.

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

Ответ 9

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

Если у вас есть метод или конструктор, который принимает параметр объекта, а рассматриваемый объект/метод не может разумно иметь дело с тем, что этот параметр равен нулю, тогда просто проверяйте и бросайте исключение NullPointerException там и потом.

Я видел, как люди изобретают правила "стиля кодирования", чтобы попытаться обойти эту проблему, например "вам не разрешено больше одной точки на линии". Но это просто поощряет программирование, которое указывает на ошибку в неправильном месте.

Ответ 10

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

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

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

Ответ 11

Поместите каждый геттер на свою линию и отлаживайте. Шаг за (F6) каждый метод, чтобы найти, какой вызов возвращает null