В 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
блокируется, когда есть необнаруженное исключение.
Последнее, безусловно, мое предпочтение, если оно доступно.