1. 程式人生 > >【Java基礎】異常處理與輸入輸出流

【Java基礎】異常處理與輸入輸出流

finally中的程式碼執行時機

try{}語句中含有return,那麼finally還會執行嗎?如果會,那麼是什麼時候執行(return前還是return後)

在Java的異常處理中,不論什麼情形,finally中的邏輯一定會執行,也就是說try{}塊裡面有return,那麼finally同樣會執行的,執行時機就是try{}中的return 之前。同時如果try{} catch{}以及finally{}塊中都有return ,那麼最終執行的return是finaally中的return,前兩個沒有機會執行。

在正常的流程以及正常的異常處理中,finally保證一定執行,但是特殊情形,比如try{}塊中呼叫了exit()那麼程式就會在try{}塊中強制退出,自然不會執行finally。
另外,邏輯沒有進入try{}而發生異常或者執行退出,那麼也不會執行finally語句塊。

異常處理原理

異常是在執行時發生的非正常情況或者錯誤。當程式違反語義規則的時候,JVM就會將其表示為一個異常並丟擲,然後被丟擲的異常就可以在catch{}塊中進行捕獲和處理。
Java中的異常也是物件,並且提供了所有異常的基類java.lang.Throwable。違反語義規則的情形:Java內建的寓意檢查,比如空指標異常和陣列越界異常;另一種情形就是使用者自定義的異常

執行時異常和普通異常

Java中異常類分為錯誤Error和異常Exception。其父類都是Throwable。Error表示程式出現了嚴重的錯誤,並且該錯誤不可恢復,常常導致程式直接終止,因此程式中不會對此類異常進行捕獲(因為Error屬於必須解決的異常,是一個正確的程式中所不應該存在的)。

Exception屬於是可恢復的異常,可以進行捕獲,主要有兩種型別:檢查異常和執行時異常。 ‘
1. 檢查異常:所有繼承自Exception的非執行時異常都是檢查異常。Java編譯器會強制進行捕獲此類異常,如IO或者SQL異常。使用場景:a. 異常的發生並不會導致程式的錯誤,進行處理後可以繼續執行後續邏輯,如資料庫連線失敗並不會退出整個應用; b. 程式依賴了外部的不可靠因素,如網路IO’
2. 執行時異常:編譯器沒有對此類異常進行強制捕獲,如果發生這種異常而程式碼沒有進行捕獲的話,會交給JVM進行處理。比如空指標異常,型別轉換異常,陣列越界異常,陣列儲存異常,緩衝區異常,算術異常。

使用異常處理的幾個原則:
1. Java的異常屬於物件,使用了多型的概念,所以如果catch的是父類,那麼catch子類的catch{}塊就永遠不會執行,所以建議是先捕獲子類
2. 儘早丟擲異常同時對捕獲的異常進行處理
3. 可以根據業務需求自定義異常類
4. 異常能處理就處理,不能處理就丟擲。比如對於一些沒有很好處理方法的異常,可以直接轉型為執行時異常拋給JVM

JavaIO流的實現機制

Java中輸入輸出都可以看做是流,流可以看做是一組有序位元組的集合即資料在裝置之間的傳輸。流的本質是資料的傳輸,根據吹的資料型別不同,流可以分為兩類:位元組流和字元流。
位元組流是以位元組8bit為單位,字元流是以字元16bit為單位位元組流和字元流的主要區別在於位元組流在處理輸入輸出資料的時候不會使用到快取,而字元流是使用快取的。字元流繼承自Reader和Writer抽象類,位元組流繼承自InputStream和OutputStream抽象類。 Java的IO設計採用了裝飾者模式,使用這種設計模式的好處是可以在執行司動態的給物件新增一些額外的職責,比繼承的設計方式更加靈活。

Java的NIO

在非阻塞IO之前(NIO: Nonblocking IO),Java是通過傳統的Socket實現基本的網路通訊功能。傳統的網路通訊採用阻塞IO,阻塞IO不僅導致程執行效率低而且在多執行緒環境下還會導致大量的程序上下文切換。在1.4時引入了非阻塞IO,NIO通過Selector Channel和Buffer來實現非阻塞IO操作。
NIO實現上使用的是Reactor設計模式,可以處理多個事件源。

Java的序列化

Java中提供兩種物件持久化方式,序列化和外部序列化。
序列化:序列化是指將物件以一串位元組進行描述的過程,序列化可以將物件的狀態寫在流裡面進行網路傳輸,或者儲存到檔案或資料庫中,在需要的時候可以反序列化出物件。在需要進行序列化的類中實現Serializable介面。

序列化的特點:
1. 如果一個類可以被序列化,那麼其子類也是可以序列化的
2. static型別的資料屬於類,transient型別的資料屬於臨時資料,因此被宣告為這兩種型別的資料 是不可以進行序列化的。

序列化使用場景(使用序列化會影響系統的效能,所以儘可能不用):
1. 需要將物件通過網路來發送或者持久化到檔案或者資料庫中
2. 序列化可以實現深複製-也就是通過序列化來構建一個物件

反序列化:將流轉化為物件
序列化和反序列化的時候,每一個類都有一個serialVersioUID,在反序列化的過程中通過serialVersioUID來判斷類的相容性,如果待序列化的物件和目標物件的serialVersioUID不同,那麼就會丟擲InvalidClassException,因此為了使序列化和反序列化正常進行,強烈建議在對需要進行序列化的類中顯式的宣告static final修飾的serialVersioUID,作用在於:
1. 提高程式執行效率,因為如果不顯式的提供,那麼程式會需要計算得到該serialVersioUID
2. 提高程式的相容性,因為不同平臺計算serialVersioUID的方式可能不一樣
3. 增強版本間的相容性,如果不顯示提供,那麼類在修改之後,可能導致新版本的類的serialVersioUID與之前不一樣,而使得序列化失敗

外部序列化:Externalizable
外部序列化與內部序列化的去唄在於序列化是內建的API,只需要實現Serializable介面即可,開發人員不需要再額外的寫序列化邏輯就可以實現物件的序列化。而外部序列化Externalizable介面中提供的兩個讀寫函式必須要開發人員來實現,因此比較複雜,但是優點是比較靈活,對需要持久化的物件可以按需序列化,相應的效率也搞一些。