Java-эквивалент события CLR UnhandledException - PullRequest
2 голосов
/ 21 июня 2010

В CLR (среде выполнения, используемой в C #, VB.NET и т. Д.) Существует способ регистрации обратного вызова, вызываемого при возникновении необработанного исключения.

Есть ли что-нибудь подобное в Java?

Я предполагаю, что это будет некоторый API, которому вы передадите объект, который реализует некоторый интерфейс с помощью одного метода.Когда генерируется исключение, и в стеке нет соответствующего catch, среда выполнения вызывает метод для зарегистрированного объекта и передает объект исключения.

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

Обновление 1.

Чтобы проиллюстрировать это, вотпример в C #:

// register custom handler for unhandled exceptions
AppDomain.CurrentDomain.UnhandledException += (sender, evt) =>
{
    Console.WriteLine("unhandled exception");
    Environment.FailFast(null);
};

try
{
    throw new NullReferenceException();
}
finally
{
    Console.WriteLine("finally is executing");
}

Дело в том, что, посылая вызов Environment.FailFast(null), я могу остановить выполнение блока finally.

Конечно же, в NET 3.5и 4.0, работающий на Windows 7, я не вижу строку "наконец-то выполняется" в выводе.Но если я закомментирую вызов FailFast, то я увижу эту строку в выходных данных.

Обновление 2.

Основываясь на ответах на этотмоя попытка воспроизвести это в Java.

// register custom handler for unhandled exceptions
Thread.currentThread().setUncaughtExceptionHandler(

    new Thread.UncaughtExceptionHandler() {

        public void uncaughtException(
                final Thread t, final Throwable e) {

            System.out.println("Uncaught exception");
            System.exit(0);
        }
    }
);

try
{
    throw new NullPointerException();
}
finally
{
    System.out.println("finally is executing");
}

Когда я запускаю это в Java 6 (1.6.0_18), я вижу:

  • наконец выполняет
  • uncaught exception

Другими словами, JRE выполняет блоки finally перед выполнением обработчика uncaught-exception.

Для некоторого фона, почему это важно, вот более сложный пример:

try
{
    try
    {
        throw new NullPointerException();
    }
    finally
    {
        System.out.println("finally is executing");
        throw new java.io.IOException();
    }
}
catch (java.io.IOException x)
{
    System.out.println("caught IOException");
}

System.out.println("program keeps running as if nothing had happened...");

Итак, есть серьезная ошибка, и я хочу, чтобы моя программа остановила и зарегистрировала трассировку стека.Но прежде чем я смогу это сделать, в стеке есть промежуточный блок finally (в реальной программе это будет отдельный метод), и он пытается получить доступ к файловой системе.Что-то идет не так.Затем немного дальше вверх по стеку, предположим, что у меня есть ловушка для IOException, потому что они не имеют большого значения для меня.

Излишне говорить, что вывод:

  • наконец выполняется
  • пойманная IOException
  • программа продолжает работать так, как будто ничего не произошло ...

Так что теперь я случайно создал ситуацию, в которой серьезные ошибкискрыты от меня.

Есть два решения:

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

Последнее, безусловно, мое предпочтение, если оно доступно.

1 Ответ

7 голосов
/ 21 июня 2010

См. Thread.setUncaughtExceptionHandler().

Обновление: как выяснилось, "необработанное / необработанное исключение", по-видимому, означает немного разные вещи в C # и Java. На первый взгляд поведение, которое вы описываете, кажется (к сожалению для вас) нормальным в Java:

Установить обработчик, вызываемый, когда этот поток внезапно завершается из-за необработанного исключения.

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

AFAIK finally блоки всегда работают на Java, поэтому ваш вариант 2 нежизнеспособен.

Вывод из обсуждения ниже

Вариант 1 - не выбрасывать что-либо в finally блоках - хотя ограничение, кажется, является единственным реальным долгосрочным решением.

Для явно регистрируемой части существует вариант 3:

try
{
    try
    {
        throw new NullPointerException();
    }
    catch (Exception x)
    {
        System.out.println("caught Exception" + x.getMessage());
        x.printStackTrace();
        throw x; // keep original behaviour
    }
    finally
    {
        System.out.println("finally is executing");
        throw new java.io.IOException();
    }
}
catch (java.io.IOException x)
{
    System.out.println("caught IOException");
}

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