1.Java异常标准
Throwable类用来表示任何可以作为异常被抛出的类。Throwable对象可以分为两类:Error用来表示编译时和系统错误(一般无需关心),Exception是可以被抛出的基本类型。
(1)特例:RuntimeException
public class NeverCaught{
static void f() {
throw new RuntimeException("From f()");
}
static void g() {
f();
}
public static void main (String[] args){
g();
}
}/*Output:
Exception in thread "main" java.lang.RuntimeException: from f()
at NeverCaught.f(NevetCaught.java:7)
at NeverCaught.g(NevetCaught.java:10)
at NeverCaught.main(NevetCaught.java:13)
*/
如果RuntimeException没有被捕获而直达main(),那么在程序退出前将调用异常的printStackTrace()方法。
2.使用finally进行清理
finally的作用:当要把除内存之外的资源恢复到它们的初始状态时,就要用到finally子句。这种需要清理的资源包括:已经打开的文件或网络连接,在屏幕上画的图形等。
异常丢失
用某些特殊的方式使用finally子句时,会发生异常丢失的现象。
try{
***
}finally{
***
}catch(Exception e){
System.out.println(e);
}
如果采用上述形式使用finally,假如在try中抛出一个异常,紧接着在finally中继续抛出一个异常,那么在catch中只会捕获到finally中抛出的异常。此时异常丢失。
还有一种更加简单的丢失异常的方式是从finally子句中返回:
public class ExceptionSilencer {
public static void main (String[] args){
try{
throw new RuntimeException();
}finally{
//Using 'return' inside the finally block will silience
//any throw Exception
return;
}
}
}
上述程序即使抛出了异常,也不会产生任何输出。
3.异常的限制
(1)当覆盖方法的时候,只能抛出在基类方法的异常说明里的列出的那些异常。
(2)异常限制对构造器不起作用。但是派生类构造器的异常说明必须包含基类构造器的异常说明。
(3)派生类构造器不能捕获基类构造器抛出的异常。
(4)派生类方法可以不抛出任何异常,即使它是基类定义的异常。
(5)还需要注意main(),如果处理的刚好是派生类对象的话,编译器只会强制要求你捕获这个类所抛出的异常,但是如果将它向上转型为基类型,那编译器就会(正确地)要求你捕获基类的异常。
4.构造器
如果在构造器内抛出了异常,那么对于构造器的清理行为就不能正常工作了。因而对于在构造阶段可能会抛出异常,并且要求清理的类,最安全的使用方式是使用嵌套的try子句。
这种通用的清理惯用法在构造器不抛出任何异常时也应该运用,其基本规则是:在创建需要清理的对象之后,立即进入一个try-finally语句块。
5.异常匹配
抛出异常的时候,异常处理系统会按照代码的书写顺序找出“最近”的处理程序。找到匹配的处理程序之后,就认为异常将得到处理,不再继续查找。
查找的时候并不要求抛出的异常同处理程序所声明的异常完全匹配。派生类的对象也可以匹配其基类的处理程序。