Почему мое NullPointerException не перехватывается в моем блоке перехвата?
У меня есть поток, в котором я перехватываю все ошибки в большом, всеобъемлющем блоке 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.
- В начале каждого из этих блоков находится System.out.println. То, что следует за этими операторами консоли, не должно иметь значения.
9 ответов
Ответ оказывается, что я идиот. Я бы объяснил, что пошло не так, но давайте просто назовем это "одна из тех ошибок".
Я на мгновение забыл, что поток, который запускал исполняемый файл, был пользовательским классом потока (чтобы обойти некоторые ошибки Nokia). Это называется run()
неоднократно между вызовами к canWait()
метод.
Метод canWait был ответственным за сбой, и запуск не был сбой вообще. В довершение ко всему, у меня слепота к консоли и я совершенно неправильно, но случайно неверно процитировал последовательность событий в моем вопросе.
Похоже, вам понадобится проб и ошибок. Могу ли я предложить:
try {
doEvilStuff();
} catch (NullPointerException ex) {
System.out.println("NPE encountered in body");
} catch (Throwable ex) {
System.out.println("Regular Throwable: " + ex.getMessage());
} finally {
etc...
}
Наличие явного перехвата для NullPointerException должно стать очевидным, если исключение находится внутри блока try или блока catch/finally.
Ладно, это дикая догадка... но это объясняет вещи.
Очевидно, ваш код на самом деле не такой - поэтому я предполагаю, что ваш блок catch (или, наконец) блок либо делает что-то, прежде чем что-то регистрирует, либо использует другой регистратор, чем блок 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?
Как вы упоминаете, вы используете Runnable
- это случайно не означает, что вы также используете несколько потоков? Если doUnsafeThings()
Метод внутренне порождает другой поток снова, и это вызывает исключение, вы можете не получить его в потоке, в котором находится ваш блок catch. См. http://java.sun.com/j2se/1.5.0/docs/api/java/lang/Thread.UncaughtExceptionHandler.html
Когда я смотрю на ваш код, кажется, что recovery () выбрасывает исключение, поэтому совет, данный Джоном, был бы превосходным.
Если вы дали нам трассировку стека, вы можете получить лучшую помощь.
Когда я пытаюсь поймать исключения, я делаю что-то вроде этого:
try {
doSomethingBad();
} catch(Exception e) {
try {
LogException(...);
} catch(Exception e) {}
} finally {
}
Я не люблю вкладывать исключения, но мне не нравится, когда мой блок catch генерирует исключения.
Как правило, перехватывать 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.
Из этих трех обстоятельств приемлемо только последнее. по этой ссылке:
Просто добавьте некоторые записи в doUnsafeThings(); чтобы увидеть, что этот метод делает то, что вы ожидаете (например, поместите try catch наконец и запишите что-нибудь)
Возможно ли, что поток будет убит каким-то другим кодом? В общем, блок finally всегда выполняется, если поток не завершен ненормально, либо System.exit(), либо чем-то подобным.
Вы уверены, что смотрите в нужном месте кода? То есть, является ли блок doUnsafeThings(), который вы защищаете, в трассировке стека?
Может быть, есть проблема с вашим методом сборки, и вы отлаживаете старую версию кода?