Как вы диагностируете, какое поле / метод вызвало исключение NullPointerException - PullRequest
1 голос
/ 22 июля 2011

Допустим, у вас есть код Java, который выглядит следующим образом:

getPerson().getParent().getSiblings().first().getName()

И в этой строке вы получите исключение NullPointerException.Как вы выясните, какой из них был нулевым?Вы можете отлаживать его и проверять каждый вызов, или вы можете временно разделить цепочку на несколько строк.

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

Ответы [ 5 ]

1 голос
/ 22 июля 2011

Интересно.

Может ли человек иметь нулевого родителя? (Разве у сексуально воспроизводящих существ нет двух родителей?)

Что если ты единственный ребенок? Что должен вернуть getSiblings ()? null или, еще лучше, пустая коллекция?

Что если у вас нет имени? Стинг или Мадонна - это имя или фамилия? Если первое, что возвращает фамилия?

Настоящая проблема здесь - дизайн. Вы не думали достаточно о том, что делать в случае нулей. Лучше понять это.

1 голос
/ 22 июля 2011

ИМХО, это лучший стиль, когда вы не помещаете в одну строку методы, которые могут выдавать npe.Тогда у вас нет такой проблемы :) Даже помещать каждый вызов в одну строку (но одну и ту же инструкцию, как method1 () \ n.method2 () и так далее), не очень хорошая идея.Простое переформатирование кода может поставить их обратно в одну строку.

Если метод может возвращать ноль, вам нужно каждый раз проверять возвращаемое значение.Если метод не должен возвращать ноль, метод получения должен содержать проверку и выдавать исключение (IllegalStateException?) Вместо возврата ноля.

Вы можете добавить к существующему коду такую ​​проверку с помощью AspectJ и veave времени загрузки (используя javaagent).

Например:

/** Throw Error if a method for creating a Point returns null */
after () returning (Point p) : 
    call(Point+ SubPoint+.create(..)) {
    if (null == p) {
        String err = "Null Point constructed when this (" 
            + thisJoinPoint.getThis() 
            + ") called target (" 
            + thisJoinPoint.getTarget() 
            + ") at join point (" 
            + thisJoinPoint.getSignature() 
            + ") from source location (" 
            + thisJoinPoint.getSourceLocation()
            + ") with args ("
            + Arrays.asList(thisJoinPoint.getArgs())
            + ")";
        throw new Error(err);
    }
}
0 голосов
/ 22 июля 2011

Я думаю, что некоторые могут сделать это намного сложнее, чем то, что запрашивает ОП

Все, что вам нужно сделать, это поместить каждый цепочечный метод в свою собственную строку.

getPerson()
.getParent()
.getSiblings()
.first()
.getName();

И вы получите правильный номер строки, который будет указывать, какой метод используется NPE (предыдущая строка возвращает ноль).

И да, вы можете делать все виды надежной проверки NPE, но иногда в конце днявам нужно просто сделать что-то, а null может быть и не ожидаться, поэтому не приукрашивайте это какой-то другой обработкой ошибок.

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

Говорить о том, что он плохой дизайн для поддержки создания цепочек, я не считаю справедливым, поскольку одна из самых популярных библиотек Javascript (jQuery) использует его постоянно (и да, это так).иногда возвращает нулевые / неопределенные значения).

0 голосов
/ 22 июля 2011

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

0 голосов
/ 22 июля 2011

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

Если вам не хочется переписывать, вы можете установить точку останова в этой строке, а затем либо добавить наблюдение для каждой функции (самое простое), либо (если ваша IDE поддерживает это) напечатать каждую функцию по одному -время в "немедленное" окно и посмотрим, что вернется.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...