異常
異常不是編譯時的錯誤(Error),異常是運行時錯誤(Exception)
?
異常處理流程
代碼出現(xiàn)錯誤后,它會先在原函數(shù)代碼內部尋找是否有try catch語句,如果沒有,則找到調用這個函數(shù)的函數(shù)內部尋找,如果還沒有就會交給java虛擬機,虛擬機會直接結束掉程序,返回異常信息.
如果異常交由 JVM 處理,JVM 會結束掉程序,并將異常信息輸出到日志中,在 Android 上體現(xiàn)為 App 閃退。為了提高用戶體驗,我們要盡可能的處理可能發(fā)生的異常.

image
異常處理
try catch
public BufferedReader readFile(String path) {
/*打開path指定路徑下的文件
* 可能拋出的異常 FileNotFoundException 文件不存在
*/
FileInputStream fis = null;
try {
//可能出現(xiàn)錯誤的代碼塊
fis = new FileInputStream(path);
} catch (FileNotFoundException e) {
//catch 可能出現(xiàn)的異常
e.printStackTrace();//打印異常信息(函數(shù)調用棧)
}
BufferedReader brd = new BufferedReader(new InputStreamReader(fis));
return brd;
}
?
-
throws
如果你不想自己處理可能發(fā)生的異常,throws可以將異常拋給調用該方法的方法進行處理,如果是 main 方法,再拋出時就會交由虛擬機處理.
public BufferedReader readFile(String path) throws FileNotFoundException {
FileInputStream fis = new FileInputStream(path);
BufferedReader brd = new BufferedReader(new InputStreamReader(fis));
return brd;
}
?
異常的分類

image
如果拋出的異常為RuntimeException的子類,那么可以不進行捕獲處理,如果是Exception的其它子類那么必須進行捕獲處理,如果未進行捕獲處理,但只要沒有調用此方法,依然可以正常運行.
根據
多態(tài),如果你不能確定拋出的的異常類型,則可以 catch 它們的父類型 Exception
try {
//可能出現(xiàn)錯誤的代碼塊
fis = new FileInputStream(path);
} catch (Exception e) {
//catch 可能出現(xiàn)的異常
e.printStackTrace();//打印異常信息(函數(shù)調用棧)
}
?
自定義異常
我們可以根據不同的業(yè)務需求,選擇不同的父類,如 RuntimeException,Exception ...
class LessMoneyException extends RuntimeException {
public LessMoneyException(String s) {
super(s);
}
}
class TooMuchMoneyException extends Exception {
public TooMuchMoneyException(String s) {
super(s);
}
}
當我們在發(fā)現(xiàn)代碼執(zhí)行過程中出現(xiàn)錯誤時,我們可以選擇不去處理這個錯誤,而是throw(拋出)一個異常,讓調用該函數(shù)的上下文來處理這個錯誤,這么做的原因通常是你再將自己實現(xiàn)的函數(shù)封裝起來,供給他人使用,那么最好的辦法不是自己處理異常,而是將異常拋給使用者,讓他根據具體情況來處理錯誤.
public int foo2(ArrayList<Integer> list){
if(list == null){
throw new NullPointerException("list is null");
}else {
return list.size();
}
}
?
注意事項
- 對于一個代碼塊來說,內部的語句在執(zhí)行過程中可能會拋出多種異常,我們可以捕獲不同類型的異常,針對具體問題做出不同的處理
public int foo1() {
String a = null;
String b = "20";
String c = "0";
int result = -1;
try {
result = Integer.valueOf(a) * Integer.valueOf(b) / Integer.valueOf(c);
} catch (NumberFormatException e) {
System.out.println("字符串轉換整數(shù)錯誤,請檢查被被轉換字符串");
} catch (ArithmeticException e) {
System.out.println("出現(xiàn)了算術異常,可能為除零錯誤");
}
return result;
}
?
- 當程序出現(xiàn)異常后,無論異常是否被處理,出現(xiàn)異常的代碼后的語句都不再被執(zhí)行,所以要注意因為異常導致的初始化及重置問題
如果你在 IDE 中編寫了如下代碼,在 return 語句出會出現(xiàn)錯誤提醒,因為 try 代碼塊中為可能出現(xiàn)異常的語句,則其內的賦值語句不一定會被成功執(zhí)行,并不能確保變量一定被初始化,同時如果 i 變量的賦值出現(xiàn)問題,j 的賦值語句完全不會被執(zhí)行.
Variable 'i' might not have been initialized
public double foo2() {
double i;
double j;
try {
i = Math.PI;
j = 1;
} catch (Exception e) {
e.printStackTrace();
}
return i;
}
?
- 可以使用
finally來對狀態(tài)進行統(tǒng)一管理,如資源清除,變量重置,關閉打開的文件等
public void trans(int card1, int card2) {//從card1向card2轉賬1000
int temp1 = card1, temp2 = card2;
try {
card1 -= 1000;
if (card1 < 0) {
throw new LessMoneyException("錢太少了");
}
card2 += 1000;
if (card2 > 1001) {
throw new TooMuchMoneyException("要那么多錢干嘛");
}
} catch (LessMoneyException e) {
e.printStackTrace();
} catch (TooMuchMoneyException e) {
e.printStackTrace();
} finally {
card1 = temp1;
card2 = temp2;
}
}