Null reference exception android

Как понять NullPointerException

Эта простая статья скорее для начинающих разработчиков 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, а не где-либо ещё.

Рассмотрим такой код:

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

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

Вот другой пример:

Снова вызываем метод handle и получаем

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

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

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

Читайте также:  Виджет ростелеком для андроид

Вот такой код (здесь может играть роль версия Java, я использую Oracle JDK 1.7.0.45):

Вызываем метод dump, получаем такое исключение:

В параметре pw не может быть null, иначе нам не удалось бы войти в метод print. Возможно, null в obj? Легко проверить, что pw.print(null) выводит строку «null» без всяких исключений. Пойдём с конца. Исключение случилось здесь:

В строке 473 возможна только одна причина NPE: обращение к методу length строки s. Значит, s содержит null. Как так могло получиться? Поднимемся по стеку выше:

В метод write передаётся результат вызова метода String.valueOf. В каком случае он может вернуть null?

Единственный возможный вариант — obj не null, но obj.toString() вернул null. Значит, ошибку надо искать в переопределённом методе toString() нашего объекта MyObject. Заметьте, в stack trace MyObject вообще не фигурировал, но проблема именно там. Такой несложный анализ может сэкономить кучу времени на попытки воспроизвести ситуацию в отладчике.

Не стоит забывать и про коварный автобоксинг. Пусть у нас такой код:

И такое исключение:

На первый взгляд единственный вариант — это null в параметре obj. Но следует взглянуть на класс MyContainer:

Мы видим, что getCount() возвращает Integer, который автоматически превращается в int именно в третьей строке TestNPE.java, а значит, если getCount() вернул null, произойдёт именно такое исключение, которое мы видим. Обнаружив класс, подобный классу MyContainer, посмотрите в истории системы контроля версий, кто его автор, и насыпьте ему крошек под одеяло.

Помните, что если метод принимает параметр int, а вы передаёте Integer null, то анбоксинг случится до вызова метода, поэтому NPE будет указывать на строку с вызовом.

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

Источник

Null Reference Exception Класс

Определение

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

Исключение, возникающее при попытке разыменования указателя NULL на объект.

Комментарии

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

Вы забыли создать экземпляр ссылочного типа. В следующем примере names объявляется, но никогда не создается экземпляр:

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

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

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

Читайте также:  Forza street android дата выхода

Дополнительные сведения об объявлении и инициализации массивов см. в разделе массивы и массивы.

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

Код в следующем примере предполагает, что Array.Find метод всегда возвращает объект, Person поле которого FirstName соответствует строке поиска. Поскольку совпадений нет, среда выполнения создает NullReferenceException исключение.

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

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

В следующем примере определяется Pages объект, который кэширует сведения о веб-страницах, которые представлены Page объектами. Example.Main Метод проверяет, имеет ли текущая веб-страница заголовок, отличный от NULL, и отображает заголовок. Однако несмотря на эту проверку, метод создает NullReferenceException исключение.

Исключение возникает, поскольку pages.CurrentPage возвращает, null Если сведения о странице не хранятся в кэше. Это исключение можно исправить, проверив значение CurrentPage свойства перед получением Page свойства текущего объекта Title , как показано в следующем примере:

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

В следующем примере определяется массив строк. for Оператор перечисляет элементы в массиве и вызывает метод каждой строки Trim перед отображением строки.

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

NullReferenceExceptionИсключение вызывается методом, который передается null . Некоторые методы проверяют передаваемые им аргументы. Если они выполняют и один из аргументов имеет значение null , метод создает System.ArgumentNullException исключение. В противном случае вызывается NullReferenceException исключение. Этот сценарий показан в следующем примере.

Чтобы устранить эту ошибку, убедитесь, что аргумент, передаваемый в метод, не имеет значение null , или обрабатывайте созданное исключение в try…catch…finally блоке. Дополнительные сведения см. в разделе Исключения.

Следующие инструкции промежуточного языка MSIL вызовут NullReferenceException : callvirt , cpblk , cpobj , initblk , ldelem. , ldelema , ldfld , ldflda , ldind. , ldlen , stelem. , stfld ,, и stind. throw unbox .

NullReferenceException использует COR_E_NULLREFERENCE HRESULT, имеющий значение 0x80004003.

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

Обработка NullReferenceException в коде выпуска

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

Однако существует много ситуаций, в которых процесс обработки ошибки может оказаться полезен:

Читайте также:  Опен диаг про последняя версия андроид

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

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

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

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

Конструкторы

Инициализирует новый экземпляр класса NullReferenceException, устанавливая в качестве значения свойства Message нового экземпляра системное сообщение с описанием ошибки: «При запросе экземпляра объекта обнаружено значение NULL». Это сообщение учитывает культуру текущей системы.

Инициализирует новый экземпляр класса NullReferenceException с сериализованными данными.

Инициализирует новый экземпляр класса NullReferenceException с указанным сообщением об ошибке.

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

Свойства

Возвращает коллекцию пар «ключ-значение», предоставляющую дополнительные сведения об исключении.

(Унаследовано от Exception) HelpLink

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

(Унаследовано от Exception) HResult

Возвращает или задает HRESULT — кодированное числовое значение, присвоенное определенному исключению.

(Унаследовано от Exception) InnerException

Возвращает экземпляр класса Exception, который вызвал текущее исключение.

(Унаследовано от Exception) Message

Возвращает сообщение, описывающее текущее исключение.

(Унаследовано от Exception) Source

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

(Унаследовано от Exception) StackTrace

Получает строковое представление непосредственных кадров в стеке вызова.

(Унаследовано от Exception) TargetSite

Возвращает метод, создавший текущее исключение.

(Унаследовано от Exception)

Методы

Определяет, равен ли указанный объект текущему объекту.

(Унаследовано от Object) GetBaseException()

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

(Унаследовано от Exception) GetHashCode()

Служит хэш-функцией по умолчанию.

(Унаследовано от Object) GetObjectData(SerializationInfo, StreamingContext)

При переопределении в производном классе задает объект SerializationInfo со сведениями об исключении.

(Унаследовано от Exception) GetType()

Возвращает тип среды выполнения текущего экземпляра.

(Унаследовано от Exception) MemberwiseClone()

Создает неполную копию текущего объекта Object.

(Унаследовано от Object) ToString()

Создает и возвращает строковое представление текущего исключения.

(Унаследовано от Exception)

События

Возникает, когда исключение сериализовано для создания объекта состояния исключения, содержащего сериализованные данные об исключении.

Источник

Оцените статью