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

Почему Java не говорит вам, какой указатель имеет значение null?

Я всегда задавался вопросом, почему JVM не говорит вам, какой указатель (или, точнее, какая переменная) является нулевым при вызове NullPointerException.

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

Есть ли какой-либо флаг компилятора или JVM, который сделает эти сообщения исключений более полезными?

4b9b3361

Ответ 1

Это потому, что разыменование всегда происходит, когда нет имени. Значение загружается в стек операнда, а затем передается одному из кодов операций JRE, которые его разыскивают. Тем не менее, стек операнда не имеет имени для связывания с нулевым значением. Все, что у него есть, - "null". С помощью некоторого умного кода отслеживания времени выполнения можно получить имя, но это добавит накладные расходы с ограниченным значением.

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

В этом примере ссылка хранится в локальном слоте 1, который сопоставляется с именем локальной переменной. Но разыменование происходит в invokevirtual инструкции, которая видит только стек "null" в стеке, а затем генерирует исключение:

15 aload_1
16 invokevirtual #5 

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

76 aload    5
78 iconst_0
79 aaload
80 invokevirtual #5

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

(myflag ? objA : objB).toString()

Ответ 2

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

Ответ 3

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

Ответ 4

Если

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

то я предлагаю:

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

Ответ 5

Это, к сожалению, так, как работает Java.

Если это "ваш" код, просто добавьте такие фрагменты, как

if (foo == null) {
  throw new NullPointerException("foo == null");
}

сразу после назначения foo. Если foo - это параметр, то сразу же проверяйте его в начале тела метода и вместо этого выведите IllegalArgumentException.

Это поможет вам прояснить ситуацию.

Ответ 6

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