Почему мое 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. 

Из этих трех обстоятельств приемлемо только последнее. по этой ссылке:

Поймать исключение NullPointerException

Просто добавьте некоторые записи в doUnsafeThings(); чтобы увидеть, что этот метод делает то, что вы ожидаете (например, поместите try catch наконец и запишите что-нибудь)

Возможно ли, что поток будет убит каким-то другим кодом? В общем, блок finally всегда выполняется, если поток не завершен ненормально, либо System.exit(), либо чем-то подобным.

  • Вы уверены, что смотрите в нужном месте кода? То есть, является ли блок doUnsafeThings(), который вы защищаете, в трассировке стека?

  • Может быть, есть проблема с вашим методом сборки, и вы отлаживаете старую версию кода?

Другие вопросы по тегам