阿里Java開發手冊思考(五)

史培培發表於2018-02-08

題圖:by pixel2013 From pixabay

上期我們分享了Java中日誌的處理(下):Java中日誌實際使用中的相關注意點

本期我們將分享Java中異常的處理

異常定義

在《java程式設計思想》中這樣定義異常:阻止當前方法或作用域繼續執行的問題。

異常分類

首先我們看下Java中異常的繼承關係:

可以看出,Throwable有兩個子類:ErrorException

  • Error
    • VirtualMachineError,典型的有StackOverFlowOutOfMemory
    • AWTError
  • Exception
    • IOException
    • ...
    • RuntimeException

Exception分為CheckedException和UncheckedException,那麼CheckedException和UncheckedException區別是什麼呢?

  • UncheckedException:派生於Error或者RuntimeException的異常
  • CheckedException:所有其他的異常

異常處理機制

異常處理機制分為:丟擲異常和捕捉異常

丟擲異常:方法上使用throws,方法內使用throw 捕捉異常:使用try-catch或者try-catch-finally

原則,正如手冊上所說:

  • 不要直接忽略異常
  • 不要用try-catch包住太多語句
  • 不要用異常處理來處理程式的正常控制流
  • 不要隨便將異常迎函式棧向上傳遞,能處理儘量處理

何時向上傳播?

  • 當你認為本異常應該由上層處理時,才向上傳播

注意點

  • finally語句塊一定會執行嗎?

不一定會,以下兩種情況finally語句塊不會執行

  1. 未執行到try語句塊
  2. try語句塊中有System.exit(0);
  • finally語句塊的執行順序

首先看沒有控制語句的情況:

public static void main(String[] args) {
	try {
		System.out.println("try block");
	} finally {
		System.out.println("finally block");
	}
}
複製程式碼

輸出沒有疑問: try block finally block

1、如果try中有控制語句(returnbreakcontinue),那finally語句塊是在控制轉義語句之前執行還是之後執行?

private static String test1() {
	System.out.println("test1()");
	return "return";
}

private static String test() {
	try {
		System.out.println("try block");
		return test1();
	} finally {
		System.out.println("finally block");
	}
}

public static void main(String[] args) {
	System.out.println(test());
}
複製程式碼

輸出: try block test1() finally block return

所以說,如果try中有控制語句(returnbreakcontinue),那finally語句塊是在控制轉義語句之前執行

2、如果catch語句中有控制語句(returnbreakcontinue),那finally語句塊是在控制轉義語句之前執行還是之後執行?

private static String test1() {
	System.out.println("test1()");
	return "return";
}

private static String test() {
	try {
		System.out.println("try block");
		System.out.println(1 / 0);
		return test1();
	} catch (Exception e) {
		System.out.println("catch block");
		return test1();
	} finally {
		System.out.println("finally block");
	}
}

public static void main(String[] args) {
	System.out.println(test());
}
複製程式碼

輸出: try block catch block test1() finally block return

所以說,如果catch語句中有控制語句(returnbreakcontinue),那finally語句塊是在控制轉義語句之前執行

  • finally裡的變數
public static int test() {
	int i = 0;
	try {
		return i;
	} finally {
		i++;
	}
}

public static void main(String[] args) {
	System.out.println(test());
}
複製程式碼

輸出: 0

咦?很奇怪,為什麼是0,而不是1呢?

通過反編譯生成的class,我們就能知道原因了

int i = 0;
try {
	return i;
} finally {
	int iTemp = i++;
}
複製程式碼

原來,i++後只是賦值給了一個新的區域性變數,i本身並沒有變,這一點和函式的形參一樣,如果傳的是引用型別的,那麼值會變,如果傳的不是引用型別,那麼值是不會改變的,改變的也只是區域性變數。

阿里Java開發手冊思考(五)

微信公眾號:碼上論劍
請關注我的個人技術微信公眾號,訂閱更多內容

相關文章