(Неизвестный источник) в трассировке стека исключений
Фон
Этот вопрос связан с Почему String.valueOf(null) выдает исключение NullPointerException?
Рассмотрим следующий фрагмент:
public class StringValueOfNull {
public static void main(String[] args) {
String.valueOf(null);
// programmer intention is to invoke valueOf(Object), but instead
// code invokes valueOf(char[]) and throws NullPointerException
}
}
Как объясняется в ответе на связанный вопрос, перегрузка Java-метода разрешает вышеупомянутую инволюцию на String.valueOf(char[])
, что по праву приводит к NullPointerException
во время выполнения.
Скомпилированный в Eclipse и javac 1.6.0_17
, это трассировка стека:
Exception in thread "main" java.lang.NullPointerException
at java.lang.String.<init>(Unknown Source)
at java.lang.String.valueOf(Unknown Source)
at StringValueOfNull.main(StringValueOfNull.java:3)
Обратите внимание, что в приведенной выше трассе стека отсутствует информация KEY: у нее нет полной подписи метода valueOf
! Он просто говорит String.valueOf(Unknown Source)
!
В большинстве ситуаций, с которыми я столкнулся, трассировки стека исключений всегда имеют полную подпись методов, которые на самом деле находятся в трассировке стека, что, конечно же, очень полезно для немедленной идентификации проблемы и основной причины, по которой трассировка стека ( который, разумеется, довольно дорог для постройки) предоставляется в первую очередь.
И все же в этом случае трассировка стека вообще не помогает. Он с треском провалился, помогая программисту идентифицировать проблему.
Как есть, я вижу три способа, которыми программист может идентифицировать проблему с приведенным выше фрагментом:
- Программист сам понимает, что метод перегружен, и по правилу разрешения в этом случае вызывается "неправильная" перегрузка
- Программист использует хорошую среду IDE, которая позволяет ему/ей быстро видеть, какой метод выбран
- В Eclipse, например, при наведении указателя мыши на указанное выше выражение быстро сообщает программисту, что
String valueOf(char[] data)
действительно выбран один
- Программист проверяет байт-код (тьфу!)
Последняя опция, вероятно, является наименее доступной, но, конечно же, является окончательным ответом (программист может неправильно понимать правило перегрузки, IDE может быть ошибкой, но байткоды всегда (?) говорят правду о том, что делается).
Вопросы
- Почему трассировка стека настолько неинформативна в этом случае в отношении сигнатур методов, которые фактически находятся в трассировке стека?
- Это из-за компилятора? Время выполнения? Что-то еще?
- В каких других (редких?) сценариях трассировка стека может не захватывать важную информацию, подобную этим?
Ответы
Ответ 1
Обычно это связано с отсутствующей информацией об отладке. Вероятно, вы используете JRE (не JDK), который не включает информацию об отладке для классов rt.jar. Попробуйте использовать полный JDK, вы получите правильные места в трассировке стека:
Exception in thread "main" java.lang.NullPointerException
at java.lang.String.<init>(String.java:177)
at java.lang.String.valueOf(String.java:2840)
at StringValueOfNull.main(StringValueOfNull.java:3)
Ответ 2
Обратите внимание, что если вы используете Ant build и если атрибут debug установлен в false в команде javac, это может произойти.
ex: если вам нужно правильное расположение в наборе трассировки debug = true в Ant build,
<javac verbose="false" srcdir="${src}" destdir="${classdir}" debug="true" includes="**/*.java">
<classpath refid="compile.classpath" />
</javac>
Ответ 3
У меня была та же проблема: для непрерывной интеграции я использую spring и apache ant.
Ошибка, которую я имел, была в файле build.xml.
Журнал изменений пола с более точным контентом был:
build.xml с ошибкой:
<javac srcdir="${src.home}" destdir="${work.home}/WEB-INF/classes">
<classpath refid="compile.classpath" />
</javac>
build.xml без ошибок:
<javac srcdir="${src.home}" destdir="${work.home}/WEB-INF/classes" debug="true">
<classpath refid="compile.classpath" />
</javac>
Внутри структуры мне не хватило смелости debug = "true"
Ответ 4
Я запустил код в Eclipse и получил следующий вывод:
public class Aloof {
public static void main(String[] args) {
String.valueOf(null);
}
}
Exception in thread "main" java.lang.NullPointerException
at java.lang.String.<init>(String.java:177)
at java.lang.String.valueOf(String.java:2840)
at mysql.Aloof.main(Aloof.java:19)
Если вы включаете полный источник (из JDK), вы можете отлаживать строку 177 в String.java
Ответ 5
Это происходит, когда в источнике нет отладочной (строковой) информации, или виртуальной машине предлагается выбросить эту информацию во время загрузки класса. Поскольку у вас есть номера строк, это не параметр VM, а класс String
отсутствует информация об отладке.
Ответ 6
В Eclipse: Предпочтения > Java > Установленные JRE. Проверенная запись должна иметь путь внутри JDK, например. C:\Program Files (x86)\Java\jdk1.7.0_55\jre.