我什么时候应该在java中使用异常

时间:2012-09-25 17:59:53

标签: java exception exception-handling

我试图理解为什么要使用例外。 假设我有一个程序,

(不使用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()查找异常详细信息?

8 个答案:

答案 0 :(得分: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仍然会锁定文件,因此你不能在不退出应用程序的情况下再次打开文件。

答案 1 :(得分:3)

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

  • 当您检测到因错误使用类而导致的错误(即编程错误)时,会抛出未经检查异常的实例,即RuntimeException
  • 的子类
  • 当您检测到由编程错误以外的其他内容(无效数据,缺少网络连接等)引起的错误时,抛出不Exception的子RuntimeException的实例

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

答案 2 :(得分:1)

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

在你的情况下,你可以打印出“这不是我想象的,不管怎样,让我们​​继续吧!”

答案 3 :(得分:1)

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

答案 4 :(得分: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);
    }
}
当看到这样的消息时,有人会根据消息知道出了什么问题,甚至可能会做些什么来修复它。

答案 5 :(得分:0)

如果您使用的是例外,请不要

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

简单地

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

您需要删除错误打印。无论如何,除了特定的例外情况之外,还要抓住一般例外。

答案 6 :(得分:0)

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

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

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

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

希望这有帮助。

答案 7 :(得分:0)

回答你原来的问题Che,“何时使用例外?”

在Java中 - 我相信你已经发现了... Java中有一些需要try / catch的方法。这些方法“抛出”异常,并且意味着。没有办法解决它。

例如,

FileUtils.readFileToString(new File("myfile.txt"));
在添加try / catch之前,

不允许编译。

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

以Java Reflection为例......

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

完全回答你的问题 -

谨慎使用Try / Catch,因为它通常会“不赞成”应用程序中的EXPECT错误。相反,在您的方法需要时使用它们。