简体   繁体   English

为什么不能用try / catch子句处理Exception e?

[英]Why can't I handle Exception e with try / catch clause?

When I compile the following code everything goes fine and output is as expected: 当我编译以下代码时,一切正常,并且输出符合预期:

class Propogate {
    public static void main(String[] args) {
        Propogate obj = new Propogate();
        try {
            obj.reverse("");
        } catch (IllegalArgumentException e) {
            System.out.println(e);
        } finally {
            System.out.println("That's all folks");
        }
    }
    String reverse(String s) {
        if(s.length() == 00) {
            throw new IllegalArgumentException();
        }
        String reversed = "";
        for(int i=s.length() - 1; i >= 0; --i) {
            reversed += s.charAt(i);
        }
        return reversed;
    }
}

Program results: 程序结果:

java.lang.IllegalArgumentException
That's all folks

However, when I run the exact same code but change the exception type from 但是,当我运行完全相同的代码但将异常类型从

IllegalArgumentException to plain old exception all I get is:Propogate.java:14: error:    
unreported exception Exception; must be caught or declared to be thrown
                        throw new Exception();
                    ^
1 error

What is special about the parent type Exception() that I can't handle it with a try / catch statement? 父类型Exception()的特殊之处是我无法使用try / catch语句来处理它? Why does IllegalArgumentException() allow me to handle it with a try / catch statement just fine. 为什么IllegalArgumentException()允许我使用try / catch语句来很好地处理它。 These are the thoughts of a being kept awake at night with the terror of failing, nay, just taking the SCJP exam. 这些就是晚上参加SCJP考试时会因失败而害怕的恐惧而保持清醒的想法。

A method which throws an exception that is not a subclass of RuntimeException must declare that it throws that Exception . 抛出不是RuntimeException的子类的异常的方法必须声明它抛出该Exception You must write 你必须写

String reverse(String s) throws Exception {

if you're going to throw an Exception with it. 如果您要抛出一个Exception Once you do that, you can catch it with a try/catch normally. 完成此操作后,您可以正常尝试/捕获它。

IllegalArgumentException s are unchecked exceptions, because they are subclasses of RuntimeException . IllegalArgumentException是未经检查的异常,因为它们是RuntimeException子类。 So the compiler isn't going to check them. 因此,编译器不会检查它们。 Non- RuntimeException objects, such as Exception , are checked by the compiler, which explains what you're seeing. 编译器会检查非RuntimeException对象(例如Exception ,这将解释您所看到的内容。

Because you're catching the exception in main() , which is the bottom of your call stack, I think it's better to cover all contingencies by having catch (Exception e) instead. 因为您正在main()捕获异常,这是调用堆栈的底部,所以我认为最好使用catch (Exception e)来覆盖所有意外catch (Exception e)

A method which throws an exception that is a subclass of RuntimeException dosn't have to declare that it throws that Exception just following the method. 引发作为RuntimeException的子类的异常的方法不必声明在该方法之后立即引发该Exception。 That's why the first code goes well. 这就是为什么第一个代码运行良好的原因。

However,when you change the exception type to Non-RuntimeException, you have to make the method throw the Exception, or the compile error will occur. 但是,将异常类型更改为Non-RuntimeException时,必须使该方法引发Exception,否则将发生编译错误。 That's why the second code goes wrong. 这就是第二个代码出错的原因。

The other answers have covered why the compiler is unhappy, and what you can do about it. 其他答案涵盖了编译器为什么不满意的原因,以及您可以采取的措施。 But I think that your real mistake is throwing Exception in the first place. 但是我认为您真正的错误是首先抛出Exception

Throwing Exception is almost always a bad idea. 抛出Exception几乎总是一个坏主意。 The reason is that if your code throws Exception , it (or someone else's code) then typically has to catch the exception. 原因是,如果您的代码抛出Exception ,则它(或其他人的代码)通常必须捕获​​该异常。 But the problem with catching Exception is that your code also catches any / all subtypes of Exception that might be thrown by your code. 但是捕获Exception的问题是您的代码还捕获了您的代码可能抛出的Exception所有子类型。 That includes unchecked exceptions that might be caused by bugs in your code, etcetera. 包括未经检查的异常,这些异常可能是由代码中的错误等引起的。

For example: 例如:

public class Test {
    private static Integer a;
    private static Integer b;

    public static void main(String[] args) {
        try {
            if (a.equals(b)) {
                throw Exception("they are the same");
            } 
            System.out.println("they are different");
        } catch (Exception ex) {
            System.out.println(ex.message());
        }
    }
}

When you run this, you will get the mysterious output "null". 运行此命令时,将得到神秘的输出“ null”。 (Exercise for reader ... figure out precisely why.) (供读者练习……准确地找出原因。)

Declaring a method as throws Exception is even worse, because now the caller is forced to either catch Exception (bad) or propagate it (worse). 将方法声明为throws Exception更加糟糕,因为现在调用者被迫捕获Exception (不良)或传播Exception (更糟)。 Methods that are declared as throws Exception are like a cancer. 声明为throws Exception方法就像癌症。

Declaring the main method as throws Exception is a special case. main方法声明为throws Exception是一个特例。 The main method is (usually) called by JVM infrastructure that is designed to cope with any exception. JVM基础结构通常调用主要方法,该方法旨在处理任何异常。 It just prints a stacktrace to standard error. 它只是将stacktrace打印到标准错误。 Even so, it is probably neater to handle the exceptions yourself. 即使这样,自己处理异常可能也更整洁。 In a "production grade" codebase, you would typically want to log the unexpected exception in the error logs. 在“生产级”代码库中,您通常希望将意外的异常记录在错误日志中。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM