需要Java';s";在例外情况下更精确地重新引用“;

需要Java';s";在例外情况下更精确地重新引用“;,java,exception,rethrow,Java,Exception,Rethrow,我很难理解在Java7和更高版本中如何精确地进行重定向。正如中所指出的,在Java 7和更高版本中,我们可以在方法声明中使用throws子句,并使用逗号分隔的方法可能抛出的特定异常列表。如果所有这些异常都是常规异常的子类型java.lang.exception,我们将能够在捕获此超类型的catch块中捕获其中任何一个异常,同时让客户端代码(例如调用方方法)知道实际发生了哪些可能的子类型异常 最初,我认为为了让客户机代码知道实际发生了哪个异常,我们需要在throws子句中指定特定异常的列表。然而,

我很难理解在Java7和更高版本中如何精确地进行重定向。正如中所指出的,在Java 7和更高版本中,我们可以在方法声明中使用
throws
子句,并使用逗号分隔的方法可能抛出的特定异常列表。如果所有这些异常都是常规异常的子类型
java.lang.exception
,我们将能够在捕获此超类型的catch块中捕获其中任何一个异常,同时让客户端代码(例如调用方方法)知道实际发生了哪些可能的子类型异常

最初,我认为为了让客户机代码知道实际发生了哪个异常,我们需要在
throws
子句中指定特定异常的列表。然而,在下面的示例中,客户机代码(
main()
方法)似乎能够检索该信息,即使我们只在被调用方法的
throws
子句中指定了异常
java.lang.exception
。因此,我的问题是:

无论方法
runException()
throws
子句是
throws ExceptionA、ExceptionB
还是
throws Exception
,为什么以下代码输出相同的值

我正在Eclipse中使用Oracle JVM-12。提前谢谢

class ExceptionA extends Exception{}
class ExceptionB extends Exception{}

public class RethrowingAndTypeChecking{
    public static void runException(char what) throws Exception{
    //public static void runException(char what) throws ExceptionA, ExceptionB{
        try{
            if(what == 'A') 
                throw new ExceptionA();
            else if (what == 'B')
                throw new ExceptionB();
        }
        catch(Exception e){
            throw e;
        }
    }

    public static void main (String args[]){
        char ch;
        for (int i=0;i<2;i++) {
            if(i==0) ch='A';
            else ch = 'B';

            try{
                runException(ch);
            }
            catch(ExceptionA e){
                System.out.print("In main(), 'catch(ExceptionA e){}', caught exception: " + e.getClass());
            }
            catch(ExceptionB e){
                System.out.print("In main(), 'catch(ExceptionB e){}', caught exception: " + e.getClass());
            }
            catch(Exception e){
                System.out.print("In main(), 'catch(Exception e){}', caught exception: " + e.getClass());
            }               
            System.out.println();
        }
    }
}

这些抛出声明是为了更明确地列出方法之外发生的事情。否则这就是普通的多态性:您使用基类组合成多个子类,但是您肯定不会更改实例,这就是为什么在运行时,在这两种情况下,异常都会被解析为它们的具体类。

通常,您不应该
捕获(异常ex)
。因为这也将捕获运行时异常。有时,捕获(Throwable t)或使用Thread.setDefaultUncaughtExceptionHandler自定义未捕获异常处理程序来捕获异常并将其显示给用户是有意义的。有时,我会捕获一个异常,将其包装在RuntimeException(或错误)中并抛出该异常

当涉及到异常时,只有当您可以对异常执行某些操作时,或者当您希望确保异常不会导致方法的其余部分无法处理时,才应该捕获异常

我个人将异常分为3种类型

  • 代码中的问题:这是您需要解决的问题
  • 用户问题:例如,如果您告诉他们输入一个数字,而他们输入“a”,这就是用户的错误
  • “Friend”异常:例如,SocketException就是一个例子。如果套接字关闭,并且您有一个线程在等待输入,它将抛出此异常,释放该线程并让您清理套接字

  • 您缺少的是需要以不同方式处理这些可能的异常的情况。您的代码正在捕获单个异常,但粗略地说,它正在执行相同的操作

    如果处理
    异常a
    的方式与处理
    异常b
    的方式大不相同,那么捕获广泛的
    异常
    将不允许您具体执行以下操作:

    catch(Exception e){
        // something unexpected happened
        // e could be an ExceptionA problem
        // e could be an ExceptionB problem
        // e could be any other unchecked exception
    }
    
    当输入
    catch(Exception e){}
    块时,异常几乎可以是任何东西,但是您只有一个通用代码块来处理它

    除此之外,如果您调用的方法声明了特定的检查异常,那么编译器可以帮助您仅处理这些异常,从而增加代码的可预测性

    try{
        runException(ch);
    } catch(ExceptionA e){
        // code specific to handling ExceptionA problems
    } catch(ExceptionB e){
        // code specific to handling ExceptionB problems
    
    } catch(ExceptionC e){ //will not compile, because not declared by runException
        // code specific to handling ExceptionB problems
    }
    

    引用@Carlos Heuberger,无论方法
    runException()
    throws
    子句是否为
    throws ExceptionA、ExceptionB
    throws Exception
    ,我的代码输出相同,因为:

    异常的运行时类型用于选择catch子句:请参阅

    无论用于引用方法
    runException()
    引发的异常对象的异常引用类型(在本例中为
    ExceptionA
    ExceptionB
    ExceptionB
    )是什么,该方法都将引发类型为
    ExceptionA
    ExceptionB
    的对象。这些对象将与
    main()
    方法的前两个catch的catch参数兼容


    在Java语言规范的段落之后,我了解到我们在方法签名的
    throws
    子句中实际指定的是异常引用类型的列表,这些类型将与从方法中抛出的任何可能的异常对象相兼容(给定类引用类型,我们可以使其指向自身的实例对象或其子类的实例对象,而不是超类)。这告诉任何其他调用方方法在使用throws子句调用该方法时可能必须处理哪些异常。在我的代码示例中,使用子句
    throws ExceptionA,ExceptionB
    的优点是,我不需要在
    main()中捕获java.lang.Exception
    。事实上,如果我选择方法
    runException()
    中的子句
    抛出异常
    ,并从
    main()中删除
    cath(异常)
    我将得到一个编译时错误。这是因为即使我们在运行时抛出
    ExceptionA
    ExceptionB
    对象,编译器也会理解该方法
    runException()
    可能抛出类型为
    exception
    的异常对象,该对象的赋值与
    main()
    中的任何catch参数都不兼容(
    exception
    ExceptionA
    ExceptionB
    的超类).

    我想我不明白你的问题。最具体的是要执行的捕获
    try{
        runException(ch);
    } catch(ExceptionA e){
        // code specific to handling ExceptionA problems
    } catch(ExceptionB e){
        // code specific to handling ExceptionB problems
    
    } catch(ExceptionC e){ //will not compile, because not declared by runException
        // code specific to handling ExceptionB problems
    }