#java #swing #awt #uncaught-exception
#java #swing #awt #неперехваченное исключение
Вопрос:
Вот некоторый код, который улавливает исключение, генерируемое в потоке отправки событий:
package com.ndh.swingjunk;
import java.awt.EventQueue;
import javax.swing.JFrame;
public class EntryPoint {
public static void main(String[] args) {
Thread.setDefaultUncaughtExceptionHandler(new MyExceptionHandler());
// System.setProperty("sun.awt.exception.handler", MyExceptionHandler.class.getName());
EventQueue.invokeLater(new Runnable()
{
public void run()
{
new SomeWindow("foo").setVisible(true);
}
});
}
}
class SomeWindow extends JFrame {
public SomeWindow(String title) {
this.setTitle(title);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
throw new RuntimeException("hello");
}
}
Я видел предупреждения о том, что исключения, генерируемые в потоке отправки событий, не обрабатываются обработчиком UncaughtExceptionHandler, но, похоже, это не относится к моему примеру; это работает одинаково, независимо от того, закомментирована строка регистрации или оставлена внутри. В моем примере что-то перепутано, или регистрация обработчика исключений с sun.awt.exception.handler
больше не требуется?
Ответ №1:
Класс EDT ( java.awt.EventDispatchThread
не ищите его в javadoc, этот класс является закрытым для пакета) сильно изменился с момента создания AWT.
В JDK6 вы можете видеть, что этот класс теперь может корректно обрабатывать исключения, возникающие внутри EDT. Обработка исключений немного сложна в текущей версии:
- если вы установили
sun.awt.exception.handler
свойство, то ваш обработчик будет вызываться для каждого исключения, вызванного кодом разработчика, вызываемым внутри EDT (совместимость с предыдущими версиями JDK гарантирована). - в противном случае любое исключение будет повторно отброшено, следовательно, остановит текущий EDT, и любое значение по умолчанию
UncaughtExceptionHandler
сможет его перехватить, как демонстрирует ваш фрагмент.
НО (и это очень важно), если вы внимательно посмотрите на код EDT, вы увидите, что этот механизм не сработает, если исключение возникает в EDT во время отображения модального диалога (я думаю, это потому, что EDT и EventQueue
управление довольно сложны, и я бы даже осмелился сказать «беспорядочно«: там много кода выглядит как взломы).
В этой точной ситуации исключения будут регистрироваться в System.err
, за исключением случаев, когда вы установили sun.awt.exception.handler
свойство. Наличие значения по умолчанию UncaughtExceptionHandler
не поможет.
Итак, мое мнение таково: ДА, вам все равно следует беспокоиться о sun.awt.exception.handler
свойстве, за исключением случаев, когда вы можете с уверенностью сказать, что ваше приложение не использует модальные диалоги (не забывайте, что JOptionPane
диалоги тоже модальны).
Комментарии:
1. К вашему сведению, это свойство было удалено в Java7. Модальные диалоги теперь используют Thread. Корректно не пойманный обработчик исключений: bugs.sun.com/view_bug.do?bug_id=6727884
Ответ №2:
Вы вызвали setDefaultUncaughtExceptionHandler
вместо setUncaughtExceptionHandler
. (Если SecurityManager
присутствует: первое требуется RuntimePermission setDefaultUncaughtExceptionHandler
; последнее как SecurityManager.checkAccess(Thread)
.)
Комментарии:
1. Хотин, я хочу, чтобы в моем пользовательском интерфейсе JavaFX всплывало окно сообщения при обнаружении неполученной ошибки. Не могли бы вы, пожалуйста, уточнить, какой вызов я должен использовать?
2. @Anil Если это ненадежный плагин / приложение для веб-запуска, оно должно быть
setUncaughtExceptionHandler
. Теоретически я считаю, что вы должны использовать JavaFX только в потоке событий, поэтому вам нужно будет установить его только один раз (но убедитесь, что в правильном потоке). AWT EDT может завершиться и быть заменен другим потоком, если нет реализованных компонентов, поэтому существует потенциальный риск того, что этого будет недостаточно, если это имеет значение.3. Hawtin JavaFX также использует задачи и рабочих в качестве фоновых потоков, и я использую их. Я не знаю, «правильно» ли это, но вот что я сделал: в потоке пользовательского интерфейса контроллера я вызвал ` Thread.currentThread().setUncaughtExceptionHandler(новый поток. UncaughtExceptionHandler() { @Override public void uncaughtException(поток t, выбрасываемый e) { OkCancelController okc = null; okc = replaceSceneContent(okc, «ok_cancel.fxml», «В приложении произошла ошибка:» e.GetMessage()); } });`