0

有时 Eclipse 会说“嘿,你应该调试这条线!!!” 但实际上并没有关闭程序。然后我可以继续玩大二,甚至经历第一次导致错误的相同事件并弹出另一个错误框!

这个bug很简单,我会修复它,我只想知道为什么有些bug是终端的,有些不是?有什么不同?

4

4 回答 4

7

编程错误可分为以下几类:

  1. 编译时错误,编译器在编译时捕获并且不纠正它们,根本不可能运行程序。
  2. 运行时错误,编译器不会捕捉到,但会使计算机处于无法自行判断该做什么的情况,例如未处理的异常。大多数时候,这会导致程序在运行时失败并崩溃。
  3. 计算机完全可以接受的逻辑错误,因为它是有效的计算机程序,但不会产生您期望的结果。计算机无法捕捉到它们,因为计算机不知道您的意图。

在实践中,让错误一出现就尽可能致命是一件好事。它使我们更快地找到它们并更容易地纠正它们。这就是为什么在 Java 等“更安全”的语言中,我们检查了异常,而未处理的异常将导致应用程序立即崩溃,而不是继续运行并可能产生不正确的结果。

于 2008-12-15T12:53:25.790 回答
2

我猜在您的情况下,这与发生异常的线程有关(您的应用程序是 GUI 应用程序,对吗?)。如果你的主线程中发生异常,它可能是终端,但如果它发生在另一个线程中,它不是终端。如果应用程序中的其他线程是守护线程,则它是主线程的终端。当线程是守护进程时,应用程序将在它们完成之前终止,无论它们的状态如何。如果它们不是守护进程,则应用程序将等待它们完成后再终止。

我不太了解 Eclipse 框架,但我想它能够处理 GUI 线程中的异常。

我包含了一个示例 Java 应用程序来说明我的示例;

public class ThreadTest {

    public static void main(String[] args) {

        Runnable test = new Runnable() {

            public void run() {
                try {
                    System.out.println("Sleeping");
                    Thread.sleep(5000);
                    System.out.println("Slept");
                } catch (InterruptedException e) {
                }
            }
        };

        Thread t = new Thread(test);
        //t.setDaemon(true);
        t.start();

        System.out.println("Waiting to fail");
        throw new RuntimeException("Error");
    }
}

取消标记 t.setDaemon(true) 行时,您将看到行为上的差异。

于 2008-12-15T13:02:35.927 回答
2

先前的答案得到了这个权利的java部分:

如果你的主线程中发生异常,它可能是终端,但如果它发生在另一个线程中,它不是终端。如果应用程序中的其他线程是守护线程,则它是主线程的终端。

更大的事实是,当没有非守护线程仍在运行时,运行应用程序的 JVM 将关闭。那,或者对 System.exit 的显式调用(或彻底的 JVM 崩溃)是 JVM 完全退出的唯一方式。

在许多更简单的 Java 应用程序中,只有 1 个非守护线程(JVM 在启动时开始运行 main() 的线程)。因为在简单的情况下,运行我们的代码的线程是唯一的非守护线程线程,我们得到的印象是未处理的异常导致 JVM 退出。这是不正确的,除非该线程恰好是唯一剩下的非守护线程。

您可以使用以下小程序向自己证明这一点:

public class TestMain {
    public static void main(String[] args) {
        Thread t1 = new Thread() {
            public void run() {
                while(true) {
                    System.out.println("A");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        System.out.println("t1 interrupted.");
                    }
                }
            }
        };
        t1.setDaemon(false);

        Thread t2 = new Thread() {
            public void run() {
                int count = 0;
                while(true) {
                    if(count < 5) {
                        System.out.println("B");
                        count++;
                    } else {
                        throw new RuntimeException("Intentional RuntimeException!");
                    }
                    try {
                        Thread.sleep(2000);
                    } catch (InterruptedException e) {
                        System.out.println("t2 interrupted.");
                    }
                }
            }
        };
        t2.setDaemon(false);
        t1.start();
        t2.start();
    }
}

如果你运行它,你会注意到你混合了“A”和“B”,直到第 5 个“B”,此时你会得到我们抛出的异常的堆栈跟踪,以及“A”' s continue (“B”s 不继续,因为该线程由于未处理的异常而刚刚死亡。)

现在,如果您返回并更改t1.setDaemon(false)t1.setDaemon(true),然后再次运行,您会看到当 t2 因异常终止时,没有剩余的非守护线程,JVM 将退出。

这回答了“为什么有些错误不能关闭 JVM”的问题。但它并没有回答为什么 Eclipse 会弹出调试器的部分问题。

答案更简单(但我对此不太确定......其他人插话):每当线程因未处理的异常而死亡时,Eclipse 调试器都会挂起。它假设您并不意味着线程死亡,并且您需要修复错误。我相信它实际上是在监视 java.lang.ThreadDeath 异常,并在它被抛出时暂停。

于 2008-12-15T16:10:44.643 回答
0

例如,想象一下您的银行使用的一款软件。

在你的储蓄账户中,他们做了以下几行:

Account -= Interest;

这显然是一个错误,但它不会使系统崩溃。

于 2008-12-15T13:15:59.300 回答