前言
最近工作的過程中遇到了一些異常鱼冀,所以解決異常的操作不夠系統(tǒng)化糕非,總結(jié)一下,示例如下站叼。
public class Fault {
public static void main(String[] args) {
Fault fault = new Fault();
fault.solveFault(3);
}
public void solveFault(int j){
Solve kick = new Solve(3, "kick");
kick.setAge(kick.getAge()-j);
solve(kick.getAge());
}
public void solve(int i){
int j = 8/i;
}
}
class Solve {
private int age;
private String name;
//接下來age和name的構(gòu)造方法和setter和getter娃兽,我就不寫了
.......
}
顯然以上結(jié)果會(huì)報(bào)異常,報(bào)異常結(jié)果如下
1. java.lang.ArithmeticException: / by zero
2. at Fault.solve(Fault.java:13)
3. at Fault.solveFault(Fault.java:9)
4. at Fault.main(Fault.java:4)
看懂報(bào)異常結(jié)果
首先要分析報(bào)異常結(jié)果尽楔,就有必要分析一下異常有什么屬性投储,異常主要包括3類屬性。
- 導(dǎo)致異常的原因(cause)
- 發(fā)生異常時(shí)的詳細(xì)解釋信息(message)
- 異常的棧幀跟蹤數(shù)組(stack trace數(shù)組)
導(dǎo)致異常的原因 cause
這個(gè)一般是由用try catch捕捉到的異常作為自己new的異常的一個(gè)cause阔馋,一般是作為構(gòu)造參數(shù)傳進(jìn)去或者調(diào)用initCause(cause)方法玛荞。這樣子就形成了一個(gè)鏈?zhǔn)降腸ause原因,因此沒有自己new異常的時(shí)候基本上調(diào)用都為null呕寝。
例如把之前的solve方法改成這樣子
public void solve(int i) throws Exception{
try {
int j = 8/i;
}catch (Exception e){
//或者是直接Exception exception = new Exception(e);
Exception exception = new Exception();
exception.initCause(e);
throw exception;
}
}
異常的附帶信息 message
這里吐槽一些勋眯,為什么我們喜歡把英文直譯過來呢?例如Exception里面分兩類Checked Exception和Runtime Exception下梢。
Checked Exception客蹋,這個(gè)就是我們在編輯的時(shí)候,一些智能一點(diǎn)的ide都會(huì)提醒我們這條語句可能會(huì)有異常孽江,要么加try catch在方法內(nèi)總結(jié)解決讶坯,要么用throws加到方法上扔給上一級處理。說實(shí)話我覺得叫做編輯期異常更容易理解岗屏,叫做受檢異常有點(diǎn)不對勁闽巩。
Runtime Exception,這個(gè)就是你運(yùn)行起來出現(xiàn)的異常担汤,叫做運(yùn)行時(shí)異常這個(gè)就直譯可以涎跨。
這個(gè)message在發(fā)生jdk自帶的異常的時(shí)候一般都會(huì)有的,然后就看你自己new的異常能不能好好處理它這個(gè)jdk自帶的異常了崭歧。
異常的棧幀跟蹤數(shù)組 stack trace數(shù)組
stack tarck數(shù)組中可以把他理解成一個(gè)棧隅很,數(shù)組后面是棧底,數(shù)組前面是棧頂,然后方法調(diào)用就是壓棧叔营,里面存儲(chǔ)的是StackTraceElement對象屋彪,這個(gè)對象里面可以找到每個(gè)方法出錯(cuò)的文件,類绒尊,方法名畜挥,行數(shù)
# 可以把上面try catch里面的換成這個(gè)
Arrays.stream(e.getStackTrace()).forEach(
k->{System.out.println("在"+k.getClassName()+"的"+k.getMethodName()+"方法.\n"
+k.getFileName()+"文件的第"+k.getLineNumber()+"行出現(xiàn)錯(cuò)誤");});
# 然后會(huì)出現(xiàn)下面的結(jié)果
在Fault的solve方法.
Fault.java文件的第21行出現(xiàn)錯(cuò)誤
在Fault的solveFault方法.
Fault.java文件的第12行出現(xiàn)錯(cuò)誤
在Fault的main方法.
Fault.java文件的第6行出現(xiàn)錯(cuò)誤
報(bào)異常結(jié)果的總結(jié)
現(xiàn)在回到之前的報(bào)異常結(jié)果。
- 第1行是異常類型(class)加上異常的信息(message)
- 第2婴谱,3蟹但,4行是從棧幀跟蹤數(shù)組里面遍歷數(shù)組元素得到的信息
- 假如自定義一個(gè)異常然后把捕捉到的exception注入進(jìn)去,那么后面還會(huì)出現(xiàn)caused by谭羔,就像這樣
java.lang.Exception: java.lang.ArithmeticException: / by zero
at Fault.solve(Fault.java:23)
at Fault.solveFault(Fault.java:12)
at Fault.main(Fault.java:6)
Caused by: java.lang.ArithmeticException: / by zero
at Fault.solve(Fault.java:21)
... 2 more
了解debug
從上面我們已經(jīng)了解到了出問題的地方在那些語句华糖,哪幾行了,一般情況下其實(shí)就可以解決部分問題了瘟裸,但是還有一部分是需要debug解決的客叉。其實(shí)java的debug調(diào)用用的是jdb。jdb和gdb原理都是差不多的话告,或者說debug是在所有程序里面都差不多的兼搏,gdb的使用看我之前的文章gdb的簡單使用 - 簡書 (jianshu.com),這里jdb的使用我是直接用ide自己集成的圖形化界面了沙郭。
到自己要判斷的行的附近debug就可以找到錯(cuò)誤了向族。