- 在catch语句中抛出当前异常,在外层被捕捉后调用printStackTrace打印信息时,异常发生起始地不会改变,不会更新为异常的新发生地。要想更新信息,可以调用fillInStackTrace()方法。如果是抛出另一种异常时,有关原来的异常发生点信息会丢失,剩下的是新的抛出点有关的信息:
import DataStructure.MyException;
/*
在catch语句中抛出当前异常,在外层被捕捉后调用printStackTrace打印信息时,
异常发生起始地不会改变,不会更新为异常的新发生地。
*/
public class Test02 {
public static void f() throws Exception{
throw new MyException();
}
public static void h() throws Exception{
try {
f();
}catch (Exception e) {
System.out.println("h()方法的printStackTrace:");
e.printStackTrace(System.out);
throw e;
}
}
public static void main(String[] args) {
try {
h();
}catch (Exception e) {
System.out.println("main()方法的printStackTrace:");
e.printStackTrace(System.out);
}
}
}
/* output:
h()方法的printStackTrace:
DataStructure.MyException
at bulidfortest.Test02.f(Test02.java:11)
at bulidfortest.Test02.h(Test02.java:16)
at bulidfortest.Test02.main(Test02.java:26)
main()方法的printStackTrace:
DataStructure.MyException
at bulidfortest.Test02.f(Test02.java:11)
at bulidfortest.Test02.h(Test02.java:16)
at bulidfortest.Test02.main(Test02.java:26)
*/
/*
要想更新信息,可以调用fillInStackTrace()方法
*/
class Test02_1 {
public static void f() throws Exception{
throw new MyException();
}
public static void h() throws Exception{
try {
f();
}catch (Exception e) {
System.out.println("h()方法的printStackTrace:");
e.printStackTrace(System.out);
throw (Exception) e.fillInStackTrace(); // 调用此方法的这一行就成为异常的新发生地了
}
}
public static void main(String[] args) {
try {
h();
}catch (Exception e) {
System.out.println("main()方法的printStackTrace:");
e.printStackTrace(System.out);
}
}
}
/* output:
h()方法的printStackTrace:
DataStructure.MyException
at bulidfortest.Test02_1.f(Test02.java:52)
at bulidfortest.Test02_1.h(Test02.java:57)
at bulidfortest.Test02_1.main(Test02.java:67)
main()方法的printStackTrace:
DataStructure.MyException
at bulidfortest.Test02_1.h(Test02.java:61)
at bulidfortest.Test02_1.main(Test02.java:67)
*/
- 无论异常是否发生,finally语句都会执行。甚至在异常没有被当前的异常处理程序捕获的情况下,异常处理机制也会在跳到更高一层的异常处理程序之前,执行finally语句:
class Test02_2 {
public static void main(String[] args) {
try {
try {
// 内层没有对该异常进行捕捉。
throw new MyException();
}finally {
// 在跳到上一层之前,先执行finally语句。
System.out.println("内层finally执行");
}
}catch (MyException e) {
e.printStackTrace(System.out);
}
}
}
/* output:
内层finally执行
DataStructure.MyException
at bulidfortest.Test02_2.main(Test02.java:91)
*/
当涉及break和continue时,finally语句也会得到执行。
- 异常丢失:
public class Test01 {
public static void main(String[] args) {
/*
以下程序发生了异常丢失,因为:
1.在内层try语句中未对异常进行捕获
2.在内层finally语句中抛出了新异常
3.外层try语句使用Exception基类来捕获异常,未使用具体异常类。(若在内层finally语句抛出了新异常,
并且使用了具体异常类试图在外层try语句捕捉内层被覆盖的异常,编译器将报错,错误就可避免。)
*/
try {
try {
f();
}finally {
System.out.println("忽略了ImportantException");
throw new TrivialException("被TrivialException代替了");
}
}catch (Exception e) {
System.out.println(e.getMessage());
}
}
public static void f() throws ImportantException {
throw new ImportantException();
}
}
class ImportantException extends Exception {
public ImportantException() {
}
public ImportantException(String message) {
super(message);
}
}
class TrivialException extends Exception {
public TrivialException() {
}
public TrivialException(String message) {
super(message);
}
}
异常丢失可以避免:
①尽量不在finally语句中抛出异常
②使用具体异常类名来捕捉异常
- 当覆盖方法时,只能抛出在基类方法的异常说明里列出的那些异常,或者它们的子类。这个限制对构造器不起作用,但是派生类构造器的异常说明必须包含基类构造器的异常说明。
- 如果派生类继承了某个基类同时也实现了某个接口,而基类和接口中有同名但异常接口不同的方法,那么在派生类中重写该方法时可以不带异常接口,但是不能将异常接口改变为接口中方法的异常接口。
- 派生类的构造器不能捕获基类构造器抛出的异常,因为调用基类构造器的super语句必须位于第一位,不能被try语句包含。
- 异常说明本身不属于方法类型的一部分,方法类型是由方法的名字和参数的类型组成的,因此,不能基于异常说明来重载方法。
- 抛出运行时异常RuntimeException时,不需要对其进行处理(try…catch或者throws),可以将编译时异常用RuntimeException包装后抛出,在需要对其进行处理时,再调用getCause( )方法获得被包装的原始异常,这样编译时错误就可以被我们“忽略”了。(RuntimeException也是Exception的子类)
class Test02_3 {
public Test02_3() {
}
public static void f(int type) {
try {
switch (type) {
case 0 -> throw new MyException();
case 1 -> throw new RuntimeException("where am i?");
}
} catch (Exception e) {
// RuntimeException异常无需处理
throw new RuntimeException(e);
}
}
public static void main(String[] args) {
try {
f(1);
}catch (RuntimeException e) {
try {
throw e.getCause();
} catch (MyException me) {
System.out.println("catch me!");
} catch (Throwable throwable) {
System.out.println(throwable.getMessage());
}
}
}
}