异常:阻止当前方法或作用域继续执行的问题。特别需要注意的,程序抛出异常,不管这个异常是否严重,都必须进行处理,决不能有运算结果不出错就是正常的想法。
先来看看异常有哪些类:
Throwable类是JAVA中所有父类,其下有两个子类:Exception与Error
Error:是指不应该试图捕获的严重问题,是不可恢复的错误,比如内存溢出或虚拟机崩溃。
Exception:合理应用程序需要捕抓的条件,Exception包括了CheckException以及RuntimeException,CheckException是指需要在程序中显性指明需要捕抓的异常,而RuntimeException则是可以在程序中不需要显性声明的异常,当发生错误时,直接抛出就是。
其类图关系如下:
先来看看Throwable类的代码,首先Throwable类继承自Serializable接口,表示可以进行序列化为对象,这有利于在网络上传输。
其中,有一个属性定义为Transient,如下:
private transient Object backtrace;
表示该属性是透明的,不需要序列化为对象的。
private StackTraceElement[] stackTrace;//描述异常轨迹的数组
StackTraceElement是一个堆栈描述类,包括了方法名、类名、文件名、行号,用于描述堆栈信息。
fillInStackTrace()是一个声明为native的函数,从调用的位置起记录新堆栈。
public String getMessage() {
return detailMessage;
}
public String getLocalizedMessage() {
return getMessage();
}
getMessage与getLocalizedMessage实际上返回的信息是一样的,如果要加入本地化信息,需要自己在子类中重写。
getCause():获取异常的起因对象,是异常链的一部分
initCause():初始化异常原因
toString():格式化异常信息
printStackTrace():打印堆栈跟踪
getOurStackTrace()获取当前堆栈信息
private native intgetStackTraceDepth();获取当前堆栈信息的深度,0表示堆栈不可用
private native StackTraceElement getStackTraceElement(int index);根据索引获取某个堆栈对象
再看看Exception类与Error类、RuntimeException:
方法基本都是继承自Throwable的,即使是构造函数也是调用父类的进行初始化
异常处理需要注意的地方:
(1) 所有的catch都用Exception 或Throwable来捕抓
try{
//dothong
}
catch(Exception e){
e.printStackTrace();
}
这样捕抓异常,虽然程序不会出错,但程序员无法知道异常的类型,并对其作分别处理,所以,异常必须尽可能捕抓且分开处理,这样才能提高程序的健壮性。
(2)接口污染
public interface aaa{
void readData() throws SQLException;
}
public class StudyInfoimplements aaa {
@Override
public void readData() throws SQLException {
try{
//do something
}
catch(SQLException e)
{
e.printStackTrace();
throw e;
}
}
}
可以看出,以上的接口污染,导致了以后所有继承该接口的类都要抛出SQLException异常,即使没有SQLException也要造一个出来。代码完全可以写成抛出RunTimeException,代码如下:
public interface aaa{
void readData();
}
public class StudyInfoimplements aaa {
@Override
public void readData(){
try{
//do something
}
catch(SQLException e)
{
throw new RuntimeException(e);
}
}
}
这样修改后,程序就变得灵活了很多。
(3) 所有的异常都比较消耗性能,捕获异常时,必须进行处理,否则异常会一层一层向外抛,直到Object对象为止。
(4)throw与throws是有区别的,throws 关键字通常被应用于声明方法时,用来指定可能抛出的异常,多个异常可以用逗号隔开。而throw关键字是抛出某个具体的对象
再提一个执行顺序的问题来加深对Exception的理解:
try{}里有一个return语句,那么紧跟在这个try之后的finally{}里的代码会不会执行,什么时候执行?是在return前还是return后?
答案:会执行,而且在return之后执行,即使是被throw出去后也会执行
因此可以看出,程序执行return时,函数并不会真正返回,只是把返回结果放到函数栈中,等finally语句执行后才真正返回。