Что такое исключения нулевого указателя ( java.lang.NullPointerException
) и что их вызывает?
Какие методы / инструменты можно использовать, чтобы определить причину, чтобы исключить преждевременное завершение программы из-за исключения?
источник
Что такое исключения нулевого указателя ( java.lang.NullPointerException
) и что их вызывает?
Какие методы / инструменты можно использовать, чтобы определить причину, чтобы исключить преждевременное завершение программы из-за исключения?
Когда вы объявляете ссылочную переменную (т.е. объект), вы действительно создаете указатель на объект. Рассмотрим следующий код, в котором вы объявляете переменную примитивного типа int
:
int x;
x = 10;
В этом примере переменная x
является int
и Java будет инициализировать его 0
для вас. Когда вы присваиваете ему значение 10
во второй строке, ваше значение 10
записывается в ячейку памяти, на которую ссылается x
.
Но когда вы пытаетесь объявить ссылочный тип , происходит что-то другое. Возьмите следующий код:
Integer num;
num = new Integer(10);
Первая строка объявляет переменную с именем num
, но на самом деле она еще не содержит примитивного значения. Вместо этого он содержит указатель (потому что тип Integer
является ссылочным типом). Поскольку вы еще не сказали, на что указывать, Java устанавливает его null
, что означает « я ни на что не указываю ».
Во второй строке new
ключевое слово используется для создания экземпляра (или создания) объекта типа, Integer
и num
этому Integer
объекту назначается переменная-указатель .
NullPointerException
Происходит , когда вы объявляете переменную , но не создать объект и присвоить переменной , прежде чем пытаться использовать содержимое переменной ( так называемый разыменования ). Таким образом, вы указываете на то, чего на самом деле не существует.
Разыменование обычно происходит при использовании .
для доступа к методу или полю или при [
индексировании массива.
Если вы попытаетесь разыменовать num
ДО создания объекта, вы получитеNullPointerException
. В самых тривиальных случаях компилятор поймает проблему и сообщит вам, что " num may not have been initialized
,", но иногда вы можете написать код, который не создает объект напрямую.
Например, у вас может быть следующий метод:
public void doSomething(SomeObject obj) {
//do something to obj
}
В этом случае вы не создаете объект obj
, а скорее предполагаете, что он был создан до вызова doSomething()
метода. Обратите внимание, что метод можно вызвать так:
doSomething(null);
В каком случае obj
это null
. Если метод предназначен для того, чтобы что-то сделать с переданным объектом, целесообразно выбросить его, NullPointerException
потому что это ошибка программиста, и программисту потребуется эта информация для целей отладки. Пожалуйста, включите имя переменной объекта в сообщение об исключении, например
Objects.requireNonNull(a, "a");
Альтернативно, могут быть случаи, когда целью метода является не только работа с переданным объектом, и, следовательно, нулевой параметр может быть приемлемым. В этом случае вам нужно будет проверить нулевой параметр и вести себя по-другому. Вы также должны объяснить это в документации. Например, doSomething()
может быть написано как:
/**
* @param obj An optional foo for ____. May be null, in which case
* the result will be ____.
*/
public void doSomething(SomeObject obj) {
if(obj == null) {
//do something
} else {
//do something else
}
}
Наконец, как определить исключение и причину, используя Stack Trace
Какие методы / инструменты можно использовать, чтобы определить причину, чтобы исключить преждевременное завершение программы из-за исключения?
Сонар с findbugs может обнаружить NPE. Может ли сонар ловить исключения нулевого указателя, вызванные JVM динамически
int a=b
могут бросить NPE, если b являетсяInteger
. Есть случаи, когда это сбивает с толку для отладки.NullPointerException
проблем в вашем коде является использование@Nullable
и@NotNull
аннотации. Следующий ответ имеет больше информации об этом. Хотя этот ответ относится конкретно к IntelliJ IDE, он также применим к другим инструментам, как это описано в комментариях. (Кстати, мне не разрешено редактировать этот ответ напрямую, возможно, автор может добавить его?)NullPointerException
Это исключения, которые возникают, когда вы пытаетесь использовать ссылку, которая указывает на отсутствие места в памяти (ноль), как если бы оно ссылалось на объект. Вызов метода с нулевой ссылкой или попытка доступа к полю с нулевой ссылкой вызовет aNullPointerException
. Это наиболее распространенные, но другие способы перечислены наNullPointerException
странице javadoc.Вероятно, самый быстрый пример кода, который я мог бы придумать для иллюстрации, был
NullPointerException
бы:На первой линии внутри
main
я явно устанавливаюObject
ссылкуobj
наnull
. Это означает, что у меня есть ссылка, но она не указывает ни на какой объект. После этого я пытаюсь обработать ссылку так, как будто она указывает на объект, вызывая метод для него. Это приводит кNullPointerException
что в местоположении, на которое указывает ссылка, нет кода для выполнения.(Это техническая проблема, но я думаю, что стоит упомянуть: ссылка, указывающая на ноль, не совпадает с указателем C, указывающим на недопустимое расположение в памяти. Нулевой указатель буквально никуда не указывает , что несколько отличается от указывая на местоположение, которое оказывается недействительным.)
источник
null
перед ее использованием, например, так . С локальными переменными компилятор поймает эту ошибку, но в этом случае это не так. Может быть, это будет полезным дополнением к вашему ответу?Что такое исключение NullPointerException?
Хорошее место для начала - JavaDocs . У них есть это покрыто:
Это также тот случай, когда вы попытаетесь использовать нулевую ссылку с
synchronized
, это также сгенерирует это исключение для JLS :Как мне это исправить?
Итак, у вас есть
NullPointerException
. Как вы это исправите? Давайте рассмотрим простой пример, который выдаетNullPointerException
:Определить нулевые значения
Первый шаг - точно определить, какие значения вызывают исключение . Для этого нам нужно сделать некоторую отладку. Важно научиться читать трассировку стека . Это покажет вам, где было выброшено исключение:
Здесь мы видим, что исключение выдается в строке 13 (в
printString
методе). Посмотрите на строку и проверьте, какие значения являются нулевыми, добавив операторы регистрации или используя отладчик . Мы выясняем, чтоs
это null, и вызовlength
метода для него вызывает исключение. Мы видим, что программа перестает генерировать исключение, когдаs.length()
удаляется из метода.Проследите, откуда берутся эти значения
Затем проверьте, откуда это значение. Следуя указаниям метода, мы видим, что
s
передаетсяprintString(name)
вprint()
метод, иthis.name
имеет значение null.Трассировка, где эти значения должны быть установлены
Где
this.name
установлен? ВsetName(String)
методе. После некоторой дополнительной отладки мы видим, что этот метод вообще не вызывается. Если метод был вызван, обязательно проверьте порядок вызова этих методов, и метод set не вызывается после метода print.Этого достаточно, чтобы дать нам решение: добавить вызов
printer.setName()
перед вызовомprinter.print()
.Другие исправления
Переменная может иметь значение по умолчанию (и
setName
может помешать ей иметь значение null):Любой метод
print
илиprintString
может проверить на ноль , например:Или вы можете создать класс так, чтобы он
name
всегда имел ненулевое значение :Смотрите также:
Я до сих пор не могу найти проблему
Если вы попытались отладить проблему и все еще не нашли решения, вы можете опубликовать вопрос для получения дополнительной помощи, но обязательно включите в него то, что вы пробовали до сих пор. Как минимум, включите в вопросе трассировку стека и отметьте важные номера строк в коде. Кроме того, попробуйте сначала упростить код (см. SSCCE ).
источник
Вопрос: что вызывает
NullPointerException
(NPE)?Как вы знаете, типы Java разделены на примитивных типов (
boolean
,int
и т.д.) и ссылочные типы . Ссылочные типы в Java позволяют использовать специальное значениеnull
которое в Java означает «нет объекта».A
NullPointerException
генерируется во время выполнения всякий раз, когда ваша программа пытается использовать a,null
как если бы это была реальная ссылка. Например, если вы напишите это:оператор, помеченный «ЗДЕСЬ», попытается запустить
length()
метод дляnull
ссылки, и это приведет кNullPointerException
.Есть много способов, которыми вы можете использовать
null
значение, которое приведет кNullPointerException
. Фактически, единственные вещи, которые вы можете сделать с помощьюnull
NPE:==
или!=
операторов, илиinstanceof
.Вопрос: Как мне прочитать трассировку стека NPE?
Предположим, что я скомпилировал и запустил программу выше:
Первое наблюдение: компиляция удалась! Проблема в программе НЕ является ошибкой компиляции. Это ошибка во время выполнения . (Некоторые IDE могут предупредить, что ваша программа всегда выдает исключение ... но стандарт
javac
компилятор этого не делает.)Второе наблюдение: когда я запускаю программу, она выводит две строки «gobbledy-gook». НЕПРАВИЛЬНО!! Это не болтунья. Это трассировка стека ... и она предоставляет важную информацию , которая поможет вам отследить ошибку в вашем коде, если вы потратите время на ее тщательное чтение.
Итак, давайте посмотрим, что он говорит:
Первая строка трассировки стека говорит вам несколько вещей:
java.lang.NullPointerException
.NullPointerException
необычно в этом отношении, потому что это редко имеет сообщение об ошибке.Вторая строка является наиболее важной в диагностике NPE.
Это говорит нам о нескольких вещах:
main
методеTest
класса.Если вы посчитаете строки в файле выше, то строка 4 будет помечена комментарием «ЗДЕСЬ».
Обратите внимание, что в более сложном примере в трассировке стека NPE будет много строк. Но вы можете быть уверены, что вторая строка (первая строка «at») скажет вам, куда был брошен NPE 1 .
Короче говоря, трассировка стека однозначно скажет нам, какой оператор программы бросил NPE.
1 - не совсем верно. Есть вещи, называемые вложенными исключениями ...
Вопрос: Как я могу отследить причину исключения NPE в моем коде?
Это сложная часть. Краткий ответ - применить логический вывод к свидетельству, предоставленному трассировкой стека, исходному коду и соответствующей документации API.
Давайте сначала проиллюстрируем на простом примере (выше). Мы начнем с того, что посмотрим на строку, которую трассировка стека сказала нам, где произошло NPE:
Как это может бросить NPE?
На самом деле, есть только один путь: это может произойти, только если
foo
имеет значениеnull
. Затем мы пытаемся запуститьlength()
методnull
и ... Взрыв!Но (я слышу, вы говорите), что если бы NPE был брошен внутри
length()
вызова метода?Ну, если бы это произошло, трассировка стека выглядела бы иначе. Первая строка «at» будет означать, что исключение было сгенерировано в некоторой строке в
java.lang.String
классе и в строке 4Test.java
будет второй строкой «at».Так откуда это
null
взялось? В этом случае это очевидно, и очевидно, что нам нужно сделать, чтобы это исправить. (Присвойте ненулевое значениеfoo
.)Хорошо, давайте попробуем немного более хитрый пример. Это потребует некоторого логического вывода .
Итак, теперь у нас есть две строки "at". Первый для этой строки:
и второй для этой строки:
Глядя на первую строку, как это может бросить NPE? Есть два способа:
bar
-null
тоbar[pos]
бросит NPE.bar[pos]
равноnull
тогда, вызовlength()
его бросит NPE.Далее нам нужно выяснить, какой из этих сценариев объясняет, что на самом деле происходит. Мы начнем с изучения первого:
Откуда
bar
берутся? Это параметр дляtest
вызова метода, и если мы посмотрим, как онtest
был вызван, мы увидим, что он исходит изfoo
статической переменной. Кроме того, мы можем ясно видеть, что мы инициализировалиfoo
ненулевое значение. Этого достаточно, чтобы предварительно отклонить это объяснение. (Теоретически, что-то еще может изменитьсяfoo
наnull
... но здесь этого не происходит.)Так что насчет нашего второго сценария? Ну, мы можем видеть, что
pos
это1
так, значит, этоfoo[1]
должно бытьnull
. Это возможно?В самом деле! И это проблема. Когда мы инициализируем так:
мы выделяем
String[]
с двумя элементами , которые инициализированы дляnull
. После этого мы не изменили содержимоеfoo
... такfoo[1]
будет и дальшеnull
.источник
Это как будто вы пытаетесь получить доступ к объекту, который есть
null
. Рассмотрим пример ниже:В настоящее время вы только что объявили этот объект, но не инициализировали или не создали его экземпляр . И всякий раз, когда вы пытаетесь получить доступ к какому-либо свойству или методу, оно выдает,
NullPointerException
что имеет смыслСмотрите также этот пример ниже:
источник
Исключение пустого указателя выдается, когда приложение пытается использовать нулевое значение в случае, когда требуется объект. Это включает:
null
объекта.null
объекта.null
как если бы это был массив.null
как если бы это был массив.null
как если бы это было значение Throwable.Приложения должны генерировать экземпляры этого класса, чтобы указать на другое незаконное использование
null
объекта.Ссылка: http://docs.oracle.com/javase/8/docs/api/java/lang/NullPointerException.html
источник
null
цели как целиsynchronized
, 2) использованиеnull
цели как целиswitch
, и распаковкаnull
.null
Указатель один , который указывает в никуда. Когда вы разыменования указателяp
, вы говорите , «дайте мне данные на месте , хранящегося в„р“. Когдаp
этоnull
указатель, расположение хранится вp
этоnowhere
, вы говорите , „дайте мне данные на месте "нигде“. Очевидно, он не может этого сделать, поэтому он выбрасываетnull pointer exception
.В общем, это потому, что что-то не было правильно инициализировано.
источник
NULL
написано какnull
в Java. И это чувствительная к регистру вещь.Уже есть много объяснений, чтобы объяснить, как это происходит и как это исправить, но вы также должны следовать передовым методам, чтобы
NullPointerException
вообще избежать их .Смотрите также: хороший список лучших практик
Я бы добавил, что очень важно, хорошо использовать
final
модификатор. Использование модификатора final, когда это применимо в JavaРезюме:
final
модификатор для обеспечения хорошей инициализации.@NotNull
и@Nullable
if("knownObject".equals(unknownObject)
valueOf()
болееtoString()
.StringUtils
методыStringUtils.isEmpty(null)
.источник
@Nullable
как указано выше) и предупреждают о возможных ошибках. Также возможно вывести и сгенерировать такие аннотации (например, IntelliJ может сделать это) на основе существующей структуры кода.if (obj==null)
Если он нулевой, то вы должны написать код для обработки этого.В Java все (кроме примитивных типов) имеет форму класса.
Если вы хотите использовать какой-либо объект, у вас есть две фазы:
Пример:
Object object;
object = new Object();
То же самое для концепции массива:
Item item[] = new Item[5];
item[0] = new Item();
Если вы не даете раздел инициализации, то
NullPointerException
возникают.источник
Исключение нулевого указателя - это индикатор того, что вы используете объект без его инициализации.
Например, ниже приведен класс ученика, который будет использовать его в нашем коде.
Код ниже дает исключение нулевого указателя.
Потому что вы используете
student
, но вы забыли инициализировать его, как в правильном коде, показанном ниже:источник
На яве все переменные, которые вы объявляете, на самом деле являются «ссылками» на объекты (или примитивы), а не на сами объекты.
Когда вы пытаетесь выполнить один метод объекта, ссылка просит живой объект выполнить этот метод. Но если ссылка ссылается на NULL (ничего, ноль, void, nada), то метод не выполняется. Затем среда выполнения сообщит вам об этом, выдав исключение NullPointerException.
Ваша ссылка «указывает» на ноль, то есть «Нуль -> Указатель».
Объект живет в пространстве памяти ВМ, и единственный способ получить к нему доступ - использовать
this
ссылки. Возьмите этот пример:И в другом месте в вашем коде:
Это важно знать: когда больше нет ссылок на объект (в приведенном выше примере, когда
reference
иotherReference
оба указывают на ноль), тогда объект «недоступен». Мы не можем работать с ним, поэтому этот объект готов к сборке мусора, и в какой-то момент виртуальная машина освободит память, используемую этим объектом, и выделит другой.источник
Другое возникновение a
NullPointerException
происходит, когда кто-то объявляет массив объектов, а затем сразу же пытается разыменовать элементы внутри него.Этого конкретного NPE можно избежать, если изменить порядок сравнения; а именно, использовать
.equals
на гарантированном ненулевом объекте.Все элементы внутри массива инициализируются своим общим начальным значением ; для любого типа массива объектов это означает, что все элементы
null
.Вы должны инициализировать элементы в массиве, прежде чем обращаться к ним или разыменовывать их.
источник
Optional
должен был возвращать ноль. Ключевое слово в порядке. Знание того, как защититься, очень важно. Это предлагает один общий случай этого и способы смягчить это.