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

StackOverflow https://stackoverflow.com/questions/1168244

Вопрос

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

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

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

Это было полезно?

Решение

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

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

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

15 aload_1
16 invokevirtual #5 

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

76 aload    5
78 iconst_0
79 aaload
80 invokevirtual #5

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

(myflag ? objA : objB).toString()

Другие советы

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

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

Если

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

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

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

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

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

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

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

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top