Главная
Блог разработчиков phpBB
 
+ 17 предустановленных модов
+ SEO-оптимизация форума
+ авторизация через соц. сети
+ защита от спама

Как осознать NullPointerException

Anna | 1.06.2014 | нет комментариев

Эта простая статья скорее для начинающих разработчиков Java, правда я зачастую вижу и опытных коллег, которые беззащитно смотрят на stack trace, уведомляющий о NullPointerException (сокращённо NPE), и не могут сделать никаких итогов без отладчика. Разумеется, до NPE своё приложение отличнее не доводить: вам помогут null-аннотации, валидация входных параметров и другие методы. Но когда пациент теснее болен, нужно его лечить, а не капать на мозги, что он ходил зимой без шапки.

Выходит, вы узнали, что ваше приложение упало с NPE, и у вас есть только stack trace. Допустимо, вам прислал его заказчик, либо вы сами увидели его в логах. Давайте посмотрим, какие итоги из него дозволено сделать.

NPE может случиться в трёх случаях:

  1. Его бросили с поддержкой throw
  2. Кто-то бросил null с поддержкой throw
  3. Кто-то пытается обратиться по null-ссылке

Во втором и третьем случае message в объекте исключения неизменно null, в первом может быть произвольным. К примеру, java.lang.System.setProperty кидает NPE с сообщением «key can’t be null», если вы передали в качестве key null. Если вы всякий входной параметр своих способов проверяете таким же образом и кидаете исключение с внятным сообщением, то вам остаток этой статьи не понадобится.

Обращение по null-ссылке может случиться в следующих случаях:

  1. Вызов нестатического способа класса
  2. Обращение (чтение либо запись) к нестатическому полю
  3. Обращение (чтение либо запись) к элементу массива
  4. Чтение length у массива
  5. Неявный вызов способа valueOf при анбоксинге (unboxing)

Значимо понимать, что эти случаи обязаны случиться именно в той строчке, на которой заканчивается stack trace, а не где-либо ещё.

Разглядим такой код:

 1: class Data {
 2:    private String val;
 3:    public Data(String val) {this.val = val;}
 4:    public String getValue() {return val;}
 5: }
 6:
 7: class Formatter {
 8:    public static String format(String value) {
 9:        return value.trim();
10:    }
11: }
12:
13: public class TestNPE {
14:    public static String handle(Formatter f, Data d) {
15:        return f.format(d.getValue());
16:    }
17: }

Откуда-то был вызван способ handle с какими-то параметрами, и вы получили:

Exception in thread "main" java.lang.NullPointerException
    at TestNPE.handle(TestNPE.java:15)

В чём повод исключения — в f, d либо d.val? Несложно подметить, что f в этой строке вообще не читается, так как способ format статический. Безусловно, обращаться к статическому способу через экземпляр класса нехорошо, но такой код встречается (мог, скажем, возникнуть позже рефакторинга). Так либо напротив значение f не может быть поводом исключения. Если бы d был не null, а d.val — null, тогда бы исключение появилось теснее внутри способа format (в девятой строчке). Подобно задача не могла быть внутри способа getValue, даже если бы он был труднее. Раз исключение в пятнадцатой строчке, остаётся одна допустимая повод: null в параметре d.

Вот иной пример:

 1: class Formatter {
 2:     public String format(String value) {
 3:         return "[" value "]";
 4:     }
 5: }
 6: 
 7: public class TestNPE {
 8:     public static String handle(Formatter f, String s) {
 9:         if(s.isEmpty()) {
10:             return "(none)";
11:         }
12:         return f.format(s.trim());
13:     }
14: }

Вновь вызываем способ handle и получаем

Exception in thread "main" java.lang.NullPointerException
	at TestNPE.handle(TestNPE.java:12)

Сейчас способ format нестатический, и f абсолютно может быть источником ошибки. Но s не может быть ни под каким соусом: в девятой строке теснее было обращение к s. Если бы s было null, исключение бы случилось в девятой строке. Просмотр логики кода перед исключением достаточно Зачастую помогает отбросить некоторые варианты.

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

if("".equals(s))

Сейчас в самой строчке обращения к полям и способам s нет, а способ equals правильно обрабатывает null, возвращая false, следственно в таком случае ошибку в двенадцатой строке мог вызвать как f, так и s. Анализируя вышестоящий код, уточняйте в документации либо исходниках, как используемые способы и конструкции реагируют на null.

Источник: programmingmaster.ru

Оставить комментарий
Форум phpBB, русская поддержка форума phpBB
Рейтинг@Mail.ru 2008 - 2017 © BB3x.ru - русская поддержка форума phpBB