Ada*_*ker 34 java exception try-catch checked-exceptions unchecked-exception
在Java中,抛出已检查异常的方法(异常或其子类型 - IOException,InterruptedException等)必须声明throws语句:
public abstract int read() throws IOException;
Run Code Online (Sandbox Code Playgroud)
不声明throws
语句的方法不能抛出已检查的异常.
public int read() { // does not compile
throw new IOException();
}
// Error: unreported exception java.io.IOException; must be caught or declared to be thrown
Run Code Online (Sandbox Code Playgroud)
但是在安全方法中捕获已检查的异常在java中仍然是合法的:
public void safeMethod() { System.out.println("I'm safe"); }
public void test() { // method guarantees not to throw checked exceptions
try {
safeMethod();
} catch (Exception e) { // catching checked exception java.lang.Exception
throw e; // so I can throw... a checked Exception?
}
}
Run Code Online (Sandbox Code Playgroud)
实际上,没有.这有点好笑:编译器知道e不是一个经过检查的异常并允许重新抛出它.事情甚至有点荒谬,这段代码不编译:
public void test() { // guarantees not to throw checked exceptions
try {
safeMethod();
} catch (Exception e) {
throw (Exception) e; // seriously?
}
}
// Error: unreported exception java.lang.Exception; must be caught or declared to be thrown
Run Code Online (Sandbox Code Playgroud)
第一个片段是一个问题的动机.
编译器知道检查的异常不能被抛出一个安全的方法 - 所以也许它应该只允许捕获未经检查的异常?
回到主要问题 - 有没有理由以这种方式实现捕获检查的异常?这只是设计中的一个缺陷还是我错过了一些重要的因素 - 可能是落后的不兼容性?如果只RuntimeException
允许在这种情况下被捕获,可能会出现什么问题?非常感谢例子.
Aas*_*set 19
如果catch子句可以捕获已检查的异常类E1并且不是对应于catch子句的try块可以抛出作为E1的子类或超类的已检查异常类的情况,那么这是编译时错误,除非E1是异常或异常的超类.
我猜这个规则早在Java 7之前就已经发生了,因为Java 7并不存在多次捕获.因此,如果你有一个try
可以抛出大量异常的块,捕获所有内容的最简单方法是捕获一个共同的超类(在最坏的情况下Exception
,或者Throwable
如果你想捕获Error
s).
请注意,您可能无法捕获与实际抛出的内容完全无关的异常类型 - 在您的示例中,捕获任何子类Throwable
都不RuntimeException
是一个错误:
try {
System.out.println("hello");
} catch (IOException e) { // compilation error
e.printStackTrace();
}
Run Code Online (Sandbox Code Playgroud)
rge*_*man 11
Java 7引入了更具包容性的异常类型检查.
但是,在Java SE 7中,您可以在rethrowException方法声明的throws子句中指定异常类型FirstException和SecondException.Java SE 7编译器可以确定语句throw e抛出的异常必须来自try块,并且try块抛出的唯一异常可以是FirstException和SecondException.
此通道被谈论一个try
特异性抛出块FirstException
和SecondException
; 即使catch
块抛出Exception
,该方法只需要声明它抛出FirstException
和SecondException
,而不是Exception
:
Run Code Online (Sandbox Code Playgroud)public void rethrowException(String exceptionName) throws FirstException, SecondException { try { // ... } catch (Exception e) { throw e; } }
这意味着编译器可以检测到抛出的唯一可能的异常类型test
是Error
s或RuntimeException
s,两者都不需要被捕获.当你throw e;
,它可以告诉,即使是静态类型Exception
,它也不需要声明或重新捕获.
但是当你把它投射到时Exception
,这会绕过那个逻辑.现在,编译器将其视为Exception
需要捕获或声明的普通代码.
将此逻辑添加到编译器的主要原因是允许程序员throws
在重新抛出Exception
捕获这些特定子类型的常规时仅在子句中指定特定的子类型.但是,在这种情况下,它允许您捕获一般Exception
而不必在子句中声明任何异常throws
,因为没有可以抛出的特定类型是已检查的异常.
这里的问题是检查/未检查的异常限制会影响允许您抛出代码的内容,而不会影响允许捕获的内容.虽然你仍然可以捕获任何类型的Exception
,但是你唯一允许实际投掷的是未经检查的那些.(这就是为什么将未经检查的异常转换为已检查的异常会破坏您的代码的原因.)
捕获未经检查的异常Exception
是有效的,因为未经检查的异常(又称RuntimeException
s)是Exception的子类,它遵循标准的多态规则; 它不把捕捉到的异常到Exception
,就像存储String
在一个Object
不转String
成一个Object
.多态性意味着一个可以容纳一个变量的变量可以包含Object
从Object
(例如a String
)派生的任何东西.同样,与Exception
所有异常类型的超类一样,类型的变量Exception
可以包含从中派生的任何类Exception
,而无需将对象转换为Exception
.考虑一下:
import java.lang.*;
// ...
public String iReturnAString() { return "Consider this!"; }
// ...
Object o = iReturnAString();
Run Code Online (Sandbox Code Playgroud)
尽管变量类型存在Object
,o
仍然存储a String
,不是吗?同样,在您的代码中:
try {
safeMethod();
} catch (Exception e) { // catching checked exception
throw e; // so I can throw... a checked Exception?
}
Run Code Online (Sandbox Code Playgroud)
这意味着实际上 "捕获任何与类兼容的东西Exception
(即Exception
从它衍生的任何东西)." 类似的逻辑也用于其他语言; 例如,在C++中,捉std::exception
也将赶上std::runtime_error
,std::logic_error
,std::bad_alloc
,任何正确定义的用户创建的例外情况,等等,因为它们都是从派生std::exception
.
tl; dr:您没有捕获已检查的异常,您正在捕获任何异常.如果将异常强制转换为已检查的异常类型,则该异常仅成为已检查的异常.
归档时间: |
|
查看次数: |
5247 次 |
最近记录: |