Java AWT队列线程中的调试异常

Java AWT队列线程中的调试异常,java,scala,debugging,intellij-idea,awt,Java,Scala,Debugging,Intellij Idea,Awt,我正在开发一个Swing应用程序,其中包含一个执行自定义绘制的组件。当我在绘制代码时出错并抛出异常时,这种情况很难调试。不会被调试器捕获,而是显示一个带有异常信息的弹出窗口。此外,由于异常是编码错误的结果,因此会反复显示 当我有幸切换到调试器时(这很困难,因为随着应用程序收到绘制请求,弹出窗口越来越多),调试控制台会向我显示异常信息,如: 严重:线程[AWT-EventQueue-0,6,main]中引发未捕获异常 。。。。堆栈如下 我的应用程序是用Scala编写的,我使用的是IntelliJ

我正在开发一个Swing应用程序,其中包含一个执行自定义绘制的组件。当我在绘制代码时出错并抛出异常时,这种情况很难调试。不会被调试器捕获,而是显示一个带有异常信息的弹出窗口。此外,由于异常是编码错误的结果,因此会反复显示

当我有幸切换到调试器时(这很困难,因为随着应用程序收到绘制请求,弹出窗口越来越多),调试控制台会向我显示异常信息,如:

严重:线程[AWT-EventQueue-0,6,main]中引发未捕获异常

。。。。堆栈如下

我的应用程序是用Scala编写的,我使用的是IntelliJ IDEA 14。调试器可以很好地处理我的未捕获主线程异常(我在
Java异常断点
中为
任何异常
断点启用了
未捕获异常
),但AWT线程中的异常不会

我已尝试按照中所述安装处理程序,但我的处理程序似乎未被触发

我希望实现以下目标(按重要性排序):

  • 避免AWT线程在异常时重新启动,或者至少防止弹出窗口显示
  • 在调试器中处理未捕获的异常,而不是在控制台中打印
  • (注意:虽然这是Scala应用程序,但我假设Java的行为相同,因此使用Java标记)

    在爪哇 您的问题是异常正在另一个线程中抛出,即事件调度线程。有两种解决方案:

    Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
        public void uncaughtException(Thread t, Throwable e) {
            logger.error("Uncaught exception in thread: " + t.getName, e);
        }
    });
    
    Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
      def uncaughtException(t: Thread, e: Throwable) {
        logger.error("Uncaught exception in thread: " + t.getName, e)
      }
    })
    
    在任何情况下,原则上您都应该在

    EventQueue.invokeLater();
    
    EventQueue.invokeLater()
    
    或者直接叫这个

    在斯卡拉 您的问题是异常正在另一个线程中抛出,即事件调度线程。有两种解决方案:

    Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
        public void uncaughtException(Thread t, Throwable e) {
            logger.error("Uncaught exception in thread: " + t.getName, e);
        }
    });
    
    Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
      def uncaughtException(t: Thread, e: Throwable) {
        logger.error("Uncaught exception in thread: " + t.getName, e)
      }
    })
    
    在任何情况下,原则上您都应该在

    EventQueue.invokeLater();
    
    EventQueue.invokeLater()
    
    根据这一点,您必须处理常规的
    异常
    EDT异常
    ,而不使用旧的
    sun.awt.Exception.handler
    hack(自Java7以来不再工作)

    这是您的
    ExceptionHandler

    public static class ExceptionHandler implements Thread.UncaughtExceptionHandler
    {
        public void uncaughtException(Thread thread, Throwable thrown)
        {
            // TODO handle your Exception here
        }
    }
    
    用法:

    // Regular Exception
    Thread.setDefaultUncaughtExceptionHandler(new ExceptionHandler());
    
    // EDT Exception
    SwingUtilities.invokeAndWait(new Runnable()
    {
        public void run()
        {
            // We are in the event dispatching thread
            Thread.currentThread().setUncaughtExceptionHandler(new ExceptionHandler());
        }
    });
    

    看起来您唯一的解决方案可能是切换到Eclipse.:-)其他解决方案需要进行编码,在异常处理程序中停止与在引发异常的确切位置停止不同

    使用下面的程序,我在Eclipse中侦听
    RuntimeException
    的捕获/未捕获实例时没有问题

    package lambda;
    
    import java.awt.Dimension;
    
    import javax.swing.JButton;
    import javax.swing.JFrame;
    import javax.swing.SwingUtilities;
    
    public class AWTExceptionTest {
        public static void main(String[] args) {
            JFrame frame = new JFrame();
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            JButton button = new JButton("Test");
            button.addActionListener(e -> { throw new RuntimeException(); });
            frame.add(button);
            frame.setSize(new Dimension(50, 50));
            SwingUtilities.invokeLater(() -> frame.setVisible(true));
        }
    }
    
    下面是它在Eclipse中调试模式下的外观

    package lambda;
    
    import java.awt.Dimension;
    
    import javax.swing.JButton;
    import javax.swing.JFrame;
    import javax.swing.SwingUtilities;
    
    public class AWTExceptionTest {
        public static void main(String[] args) {
            JFrame frame = new JFrame();
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            JButton button = new JButton("Test");
            button.addActionListener(e -> { throw new RuntimeException(); });
            frame.add(button);
            frame.setSize(new Dimension(50, 50));
            SwingUtilities.invokeLater(() -> frame.setVisible(true));
        }
    }
    

    简单来说,要回答您的两个问题,请使用EventQueue,如果您希望看到其他线程异常,请设置默认的未捕获异常处理程序。正如我在问题中所述,按照中所述安装的处理程序不会触发我。应该吗?答案很古老,它仍然有效吗?我不明白EventQueue与我的问题有什么关系-它如何影响异常处理?我说的是来自paintComponent的异常,它已经在EDT中执行了-我应该如何处理这里的EventQueue?EventQueue-虽然异常可能来自EDT,但可能是其他什么东西正在访问另一个线程中的资源导致了错误,例如修改一个列表,应该在EDT上执行。根据现有信息,这似乎是一个试图回答问题的理由,可惜它被否决了。太好了,谢谢-这就是我错过的。您是否知道(或能够了解)为什么setDefaultUncaughtExceptionHandler对于EDT是不够的?它有自己的处理程序吗?或者setDefaultUncaughtExceptionHandler是否不适用于已启动的线程?你链接的那篇文章很好,但它似乎不能解释这一点。我不知道。好问题:)现在接受了,但仍在等待悬赏奖,也许有人会提供更多细节。你的问题让我进一步推动了我的调查。事实上,根据所述,
    getDefaultUncaughtExceptionHandler
    从未在
    EventDispatchThread
    中使用。相反,在方法
    processException
    中显式调用了
    getUncaughtExceptionHandler()。这解释了为什么
    setDefaultUncaughtExceptionHandler
    不够。只有一个EDT。我们是否需要调用Thread.currentThread().setUncaughtExceptionHandler(新的ExceptionHandler());每次我们使用invokeAndWait()和invokeLater()时,我看到您在RuntimeException上设置了断点,无论捕获还是未捕获。这可以在任何IDE中完成,但它捕获了太多的异常,甚至是代码处理得很好的异常。@Suma我有它,因为我设置了它。在Eclipse中,将其配置为只侦听未捕获的异常是没有问题的。IntelliJ也是如此,因此,迁移到Eclipse不太可能在这方面对我有所帮助。恐怕如果您尝试一下,您会发现EDT异常并非未经处理(@Suma你是对的。看起来所有的异常都在EDT中被捕获。我认为线程中有一个很大的try块,它捕获了所有的
    Throwable
    实例,因此它不会死,因此不必重新启动。如果我发现了什么,我会寻找另一个解决方案并相应地更新答案。这同意我所看到的。令我惊讶的是,按照ToYonos的回答安装setUncaughtExceptionHandler是有效的。查看源代码,这是因为pumpOneEventForFilters调用getUncaughtExceptionHandler().uncaughtException(通过processException)在您提到的大try块的捕获中,我可以将断点放在处理程序中,但这并不理想,因为调试程序不会在抛出异常时停止,而是在EDT捕获异常并将其传递给han之后停止