Почему мое исключение NullPointerException не перехватывается в моем блоке catch?
-
13-09-2019 - |
Вопрос
У меня есть поток, в котором я улавливаю все ошибки в большом, всеобъемлющем блоке catch.Я делаю это для того, чтобы я мог сообщить о любой ошибке, а не только ожидаемой, в моем приложении.Мой Runnable выглядит следующим образом:
public final void run()
{
try
{
System.out.println("Do things"); /* [1] */
doUnsafeThings();
}
catch (Throwable t)
{
System.out.println("Catch"); /* [2] */
recover();
}
finally
{
System.out.println("Finally"); /* [3] */
}
}
Я бы ожидал, что NPE будет пойман блоком Throwable catch.Вместо этого выходные данные в [2] не печатаются, как и в [3].Выводится на печать в [1].
Что я действительно получаю на консоли, так это:
Uncaught exception java/lang/NullPointerException.
Что, черт возьми, здесь происходит?
Для судебных протоколов я использую J2ME, и это работает в эмуляторе Sun WTK v2.5.2.
У меня возникает соблазн списать это на изворотливость реализации JVM, но я не могу избавиться от ощущения, что я просто чего-то не понимаю.
Поясняю во избежание сомнений (поскольку пример кода явно изменен по сравнению с моим производственным кодом)
- В методе run нет ничего за пределами блока try / catch/finally в методе run.
- В начале каждого из этих блоков есть System.out.println - То, что следует за этими консольными инструкциями, не должно иметь значения.
Решение
В результате получается, что я идиот.Я бы объяснил, что пошло не так, но давайте просто назовем это "одной из тех ошибок".
Я на мгновение забыл, что поток, который запускал runnable, был пользовательским классом thread (чтобы обойти некоторые ошибки Nokia).Это называлось run()
неоднократно между вызовами в canWait()
способ.
Метод canWait был ответственен за сбой, а run вообще не был сбоем.В довершение всего, у меня консольная слепота, и я полностью, но случайно неправильно процитировал последовательность событий в моем вопросе.
Другие советы
Похоже, вам понадобятся некоторые методы проб и ошибок.Могу я предложить:
try {
doEvilStuff();
} catch (NullPointerException ex) {
System.out.println("NPE encountered in body");
} catch (Throwable ex) {
System.out.println("Regular Throwable: " + ex.getMessage());
} finally {
etc...
}
Имея явный catch для NullPointerException, должно стать очевидным, является ли исключение из блока try или блока catch / finally .
Ладно, это смелое предположение...но это бы многое объяснило.
Очевидно, что ваш код не является на самом деле это - итак, я предполагаю, что ваш блок catch (или finally) либо что-то делает, прежде чем что-либо регистрировать, или он использует другой регистратор, чем блок try.В любом случае, я подозреваю, что либо блок catch, либо блок finally генерируют исключение.
Я не предполагаю, что у вас есть трассировка стека...
Редактировать:Хорошо, если это просто System.out.println
, есть ли в этом споре что-то такое, что может взорваться?Например:
catch (Throwable t) {
// Will go bang if t.getCause() returns null
System.out.println(t.getCause().getMessage());
}
Если это просто System.out.println("Constant")
тогда это очень странно.
Знаете ли вы (напримериз строк журнала внутри блока try) как далеко на самом деле продвинулся блок try?
Когда я посмотрел на ваш код, мне показалось, что recover() выдает исключение, поэтому совету, данному Джоном, было бы замечательно последовать.
Если вы предоставили нам трассировку стека, вы можете получить лучшую помощь.
Когда я пытаюсь перехватить исключения, я делаю что-то вроде этого:
try {
doSomethingBad();
} catch(Exception e) {
try {
LogException(...);
} catch(Exception e) {}
} finally {
}
Мне не нравится вкладывать исключения, но мне не нравится, что мой блок catch генерирует исключения.
Как вы упомянули, вы используете Runnable
- это случайно не означает, что вы также используете несколько потоков?Если в doUnsafeThings()
метод снова внутренне порождает другой поток, и это создает исключение, вы можете не получить его в потоке, которым является ваш блок catch.Видишь http://java.sun.com/j2se/1.5.0/docs/api/java/lang/Thread .UncaughtExceptionHandler.html
Как правило, перехватывать исключение NullPointerException - плохая практика.
Программисты обычно перехватывают исключение NullPointerException при трех обстоятельствах:
The program contains a null pointer dereference. Catching the resulting exception was easier than fixing the underlying problem.
The program explicitly throws a NullPointerException to signal an error condition.
The code is part of a test harness that supplies unexpected input to the classes under test.
Из этих трех обстоятельств приемлемо только последнее.перейдя по этой ссылке:
Возможно ли, что поток прерывается каким-то другим кодом?В общем случае блок finally всегда выполняется, если поток не завершается ненормально, либо System.exit(), либо чем-то подобным.
Вы уверены, что смотрите в нужном месте кода?Т.е. является ли блок doUnsafeThings(), который вы защищаете, частью трассировки стека?
Может быть, есть проблема с вашим методом сборки, и вы отлаживаете старую версию кода?
просто добавьте немного протоколирования в doUnsafeThings();чтобы увидеть, делает ли этот метод то, что вы ожидаете (например, установите try catch наконец и запишите что-нибудь)