12.7 Java標準異常
Throwable可以表示任何作爲異常被拋出的類,其可分爲兩類對象:Error和Exception。
Error表示編譯時和系統錯誤,一般不需關心;
Exception表示可以被拋出的基本類型,通常關心該類型。
異常的名稱都是可以望文知意的。
12.7.1 特例:RuntimeException
運行時異常由Java虛擬機自動拋出,不必在異常說明中列出,在編譯時也不檢查這類異常,也無需捕獲這類異常。
12.8 使用finally進行清理
finally子句,無論try塊中是否拋出異常,finally子句中的代碼都會被執行。
try {
// The guarded region: Dangerous activities
// that might throw A, B or C
} catch(A a1) {
// Handler for situation A
} catch(B b1) {
// Handler for situation B
} catch(C c1) {
// Handler for situation C
} finally {
// Activities that happen every time
}
12.8.1 finally用來做什麼
把除內存之外的資源恢復到初始狀態,就需要用到finally子句。如:
1) 已經打開的文件或網絡連接;
2) 在屏幕上畫的圖形;
3) 外部世界的某個開關。
12.8.2 在return中使用finally
因爲finally子句總是會被執行,所以在一個方法中,可以從多個點返回,並且可以保證重要的清理工作仍舊會被執行。
package com.mzm.chapter12;
/**
* Created by 蒙卓明 on 2017/10/22.
*/
public class MultipleReturns {
public static void f(int i){
System.out.println("Initialization that requires cleanup");
try{
System.out.println("Point 1");
if(i == 1){
return;
}
System.out.println("Point 2");
if(i == 2){
return;
}
System.out.println("Point 3");
if(i == 3){
return;
}
System.out.println("End");
return;
} finally {
System.out.println("Performing cleanup");
}
}
public static void main(String[] args){
for(int i = 1; i <= 4; i++){
f(i);
}
}
}
12.8.3 缺憾:異常丟失
在某些情況下使用finally子句,可使異常被忽略。
package com.mzm.chapter12;
/**
*
*/
public class LostMessage {
void f() throws VeryImportantException {
throw new VeryImportantException();
}
void dispose() throws HoHumException {
throw new HoHumException();
}
public static void main(String[] args) throws HoHumException {
try{
LostMessage lm = new LostMessage();
try{
lm.f();
} finally {
lm.dispose();
}
}catch (Exception e) {
System.out.println(e);
}
}
}
class VeryImportantException extends Exception{
public String toString(){
return "A very important exception!";
}
}
class HoHumException extends Exception{
public String toString(){
return "A trivial exception";
}
}
VeryImportantException消失,其被finally子句中的HoHumException所取代。
package com.mzm.chapter12;
/**
* 丟失異常
*
*/
public class ExceptionSilencer {
public static void main(String[] args){
try{
throw new RuntimeException();
} finally {
//異常被忽略
return;
}
}
}
12.9 異常的限制
當覆蓋方法時,只能拋出在父類方法的異常說明中所列的異常,也可以不拋異常,只是不能拋出父類相應方法異常說明之外的異常。
針對構造器而言,子類的構造器的異常說明必須包含父類的構造器的異常說明,並且不能捕獲父類構造器拋出的異常。
不能基於異常說明來重載方法。
12.10 構造器
在構造器中出現異常的情況,不要再finally子句中執行清理工作。
package com.mzm.chapter12;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
/**
* Created by 蒙卓明 on 2017/10/28.
*/
public class InputFile {
private BufferedReader in;
public InputFile(String fname) throws FileNotFoundException {
try {
in = new BufferedReader(new FileReader(fname));
} catch (FileNotFoundException e) {
System.out.println("Could not open " + fname);
throw e;
} catch (Exception e) {
try{
in.close();
} catch (IOException e1) {
System.out.println("in.close() unsuccessful");
}
throw e;
} finally {
//不建議在此處執行清理工作,因爲文件未成功打開
}
}
/**
* 獲取文件的下一行
* @return 文件的下一行內容的字符串
*/
public String getLine() {
String s;
try{
s = in.readLine();
} catch (IOException e) {
throw new RuntimeException("readLine() failed");
}
return s;
}
public void dispose() {
try{
in.close();
System.out.println("dispose() successful");
} catch (IOException e) {
throw new RuntimeException("in.close() failed");
}
}
}
12.11 異常匹配
拋出異常時,異常系統會按照就近原則找出最近的處理程序。原則上再編寫代碼時,子異常類在前,父異常類在後。
12.12 其他可選方式
開發異常程序的初衷是爲了方便程序員處理錯誤。
異常處理的重要原則:只有在知道如何處理的情況下才捕獲異常。
異常處理的目標:將異常發生地點與異常處理代碼分離。
12.12.3 把異常傳遞給控制檯
即在main()方法上加上異常說明,但是此種方式不推薦。
12.12.4 把”被檢查的異常”轉換爲”不檢查的異常”
實際上就是異常轉型,將編譯時異常轉型成爲運行時異常。
try {
// ... to do somrthing useful
} catch (IDontKonwWhatToDoWithThisCheckedException e) {
throw new RuntimeException(e);
}
12.13 異常使用指南
1) 在知道如何處理的情況下才捕獲異常;
2) 解決問題並且重新調用產生異常的方法;
3) 進行少許修補,然後繞過異常發生的地方繼續執行;
4) 用別的數據進行計算,以代替方法預計會返回的值;
5) 把當前運行環境下能做的事情儘量做完,然後把相同的異常拋到更高層;
6) 把當前運行環境下能做的事情儘量做完,然後把不同的異常拋到更高層;
7) 終止程序;
8) 進行簡化;
9) 讓類庫和程序更安全。