0

我试图理解为什么要使用异常。假设如果我有一个程序,

(不使用 try/catch)

public class ExceptionExample {

private static String str;

public static void main(String[] args) {
    System.out.println(str.length());
}

我有异常

Exception in thread "main" java.lang.NullPointerException
at com.Hello.ExceptionExample.ExceptionExample.main(ExceptionExample.java:22)

现在使用 try/catch,

public class ExceptionExample {

private static String str;

public static void main(String[] args) {
    try {
        System.out.println(str.length());
    } catch(NullPointerException npe) {
        npe.printStackTrace();
    }
}

}

我有异常,

java.lang.NullPointerException
at com.Hello.ExceptionExample.ExceptionExample.main(ExceptionExample.java:9)

现在我的问题是,

在这两种情况下,我都打印了相同的消息。那么使用try/catch有什么用呢?和

捕获异常后我们可以做什么,在这种情况下,我已经打印了堆栈跟踪。catch 是否仅用于打印跟踪或使用 getMessage() 或 getClass() 查找异常详细信息?

4

8 回答 8

5

其实差别还是蛮大的。

取第一个并在打印后添加一行:

public class ExceptionExample {

    private static String str;

    public static void main(String[] args) {
        System.out.println(str.length());
        System.out.println("Does this execute?");
    }
}

您会看到它Does this execute?没有被打印出来,因为异常会中断代码流并在没有被捕获时停止它。

另一方面:

public class ExceptionExample {

    private static String str;

    public static void main(String[] args) {
        try {
            System.out.println(str.length());
        } catch(NullPointerException npe) {
            npe.printStackTrace();
        }
        System.out.println("Does this execute?");
    }
}

将打印堆栈跟踪 Does this execute?. 那是因为捕获异常就像是说,“我们将在这里处理并继续执行。”

另一种说法,catch块是错误恢复应该发生的地方,所以如果发生错误但我们可以从中恢复,我们将恢复代码放在那里。

编辑:

这是一些错误恢复的示例。假设我们有一个不存在的文件C:\nonexistentfile.txt。我们想尝试打开它,如果找不到,向用户显示一条消息,说它丢失了。这可以通过在FileNotFoundException此处捕获生成的内容来完成:

// Here, we declare "throws IOException" to say someone else needs to handle it
// In this particular case, IOException will only be thrown if an error occurs while reading the file
public static void printFileToConsole() throws IOException {
    File nonExistent = new File("C:/nonexistentfile.txt");
    Scanner scanner = null;
    try {
        Scanner scanner = new Scanner(nonExistent);
        while (scanner.hasNextLine()) {
            System.out.println(scanner.nextLine());
        }
    } catch (FileNotFoundException ex) {
        // The file wasn't found, show the user a message
        // Note use of "err" instead of "out", this is the error output
        System.err.println("File not found: " + nonExistent);
        // Here, we could recover by creating the file, for example
    } finally {
        if (scanner != null) {
            scanner.close();
        }
    }
}

所以这里有几点需要注意:

  1. 我们捕获FileNotFoundException并使用自定义错误消息,而不是打印堆栈跟踪。与打印堆栈跟踪相比,我们的错误消息更清晰、更人性化。在 GUI 应用程序中,用户甚至可能看不到控制台,因此这可能是向用户显示错误对话框的代码。仅仅因为该文件不存在并不意味着我们必须停止执行我们的代码。
  2. 我们throws IOException在方法签名中声明,而不是在FileNotFoundException. 在这种特殊情况下,IOException如果我们无法读取文件,即使它存在,也会在此处抛出。对于这种方法,我们说处理我们在读取文件时遇到的错误不是我们的责任。这是一个如何声明不可恢复错误的示例(这里的不可恢复,我的意思是不可恢复,它可能在更远的地方可以恢复,例如在调用的方法中printFileToConsole)。
  3. 我不小心在finally这里介绍了该块,所以我将解释它的作用。它保证如果Scanner在我们读取文件时打开并发生错误,Scanner则将关闭。这很重要,原因有很多,最值得注意的是,如果您不关闭它,Java 仍然会锁定该文件,因此您无法在不退出应用程序的情况下再次打开该文件。
于 2012-09-25T18:06:46.857 回答
3

有两种情况应该抛出异常:

  • 当您检测到因不正确使用您的类(即编程错误)而导致的错误时,抛出一个未经检查的异常实例,即RuntimeException
  • 当您检测到不是由编程错误(无效数据、缺少网络连接等)引起的错误时,抛出一个Exception不属于子类的实例RuntimeException

您应该捕获第二种异常,而不是第一种异常。此外,如果您的程序有纠正异常情况的措施,您应该捕获异常;例如,如果您检测到连接丢失,您的程序可以让用户重新连接到网络并重试该操作。在您的代码无法充分处理异常的情况下,让它传播到可以处理它的层。

于 2012-09-25T18:05:18.240 回答
1

try/catch 将防止您的应用程序崩溃或准确地说 - 如果满足意外条件,执行将不会停止。您可以将“有风险”的代码包装在 try 块中,并在 catch 块中处理该异常。通过处理,这意味着对那个条件做一些事情并继续执行。如果没有 try/catch,执行会在出错行停止,之后的任何代码都不会执行。

在您的情况下,您可以打印“这不是我所期望的,无论如何,让我们继续吧!”

于 2012-09-25T18:05:47.737 回答
1

假设您已连接到数据库,但在读取记录时,它会引发一些异常。现在在这种特殊情况下,您可以在 finally 块中关闭连接。您只是在这里避免了内存泄漏。我的意思是,即使通过捕获和处理抛出异常,您也可以执行您的任务。

于 2012-09-25T18:06:50.107 回答
1

在您给出的示例中,您是对的,没有任何好处。

您应该只在以下情况下捕获异常

  • 你可以做一些事情(报告、添加信息、修复情况),或者
  • 您必须这样做,因为已检查的异常会迫使您

异常的通常“处理”是将情况记录到您选择的日志文件中,添加任何相关的上下文相关信息,然后让流程继续进行。添加上下文信息极大地有助于解决问题。所以,在你的例子中,你可以做到

public static void main(String[] args) {
    try {
        System.out.println(str.length());
    } catch(NullPointerException npe) {
        System.err.println(
           "Tried looking up str.length from internal str variable,"
               +" but we got an exception with message: "
               + npe.getMessage());
        npe.printStackTrace(System.err);
    }
}

当查看这样的消息时,有人会根据消息知道出了什么问题,甚至可能会采取什么措施来解决它。

于 2012-09-25T18:07:24.013 回答
0

如果您使用异常,请不要

 catch(NullPointerException npe) {
    npe.printStackTrace();
}

简单地

  catch(NullPointerException npe) {
        //error handling code
    }

您可以删除错误打印。无论如何,捕获一般异常而不仅仅是特定异常。

于 2012-09-25T18:03:31.413 回答
0

如果你看一下这两个例外,它们实际上是不同的。第一个是指第 22 行,而第二个是指第 9 行。听起来像添加 try/catch 捕获了第一个异常,但另一行代码也抛出了异常。

因此,抛出异常是因为您从未创建新字符串或为字符串设置值,除非它是在未显示的部分代码中完成的。

添加 try/catch 块对于您几乎无法控制的对象非常有帮助,因此如果这些对象不是预期的(例如 null),您可以正确处理问题。

字符串通常是您首先要实例化的东西,因此您通常不必担心使用 try/catch。

希望这可以帮助。

于 2012-09-25T18:08:44.390 回答
0

回答您最初的问题 Che,“何时使用例外?”

在 Java 中——我相信你已经发现了……Java 中有某些方法需要 try/catch。这些方法“抛出”异常,并且旨在。没有其他办法了。

例如,

FileUtils.readFileToString(new File("myfile.txt"));

在添加 try/catch 之前不会让您编译。

另一方面,异常非常有用,因为您可以从中获得什么。

以 Java 反射为例...

try { Class.forName("MyClass").getConstructor().newInstance(); }
catch ( ClassNotFoundException x ) { // oh it doesnt exist.. do something else with it.

因此,要完全回答您的问题-

谨慎使用 Try/Catch,因为在您的应用程序中预期错误通常会“皱眉”。相反,当您的方法需要它们时使用它们。

于 2012-09-25T18:12:00.940 回答