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

(Неизвестный источник) в трассировке стека исключений

Фон

Этот вопрос связан с Почему 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 может быть ошибкой, но байткоды всегда (?) говорят правду о том, что делается).


Вопросы

  • Почему трассировка стека настолько неинформативна в этом случае в отношении сигнатур методов, которые фактически находятся в трассировке стека?
    • Это из-за компилятора? Время выполнения? Что-то еще?
  • В каких других (редких?) сценариях трассировка стека может не захватывать важную информацию, подобную этим?
4b9b3361

Ответ 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.