[Java 101 基礎篇] Java程式出錯的九種最佳處理方式 ! ( 前篇 )

前言:  通常我們程式執行正常的時候,一切都很美好。但是月有陰晴圓缺,往往都會有意外發生。這篇就是來分享一下遇到意外時,該如何處理 ~

像是下面這張圖,相信大家很常見到 ~ 就是一個常見的情境 ~

在開始進入正題(Exception Handling)之前 ,先說明一下 Java 跟 Exception 關係 ~


(* Exception 跟 Error 以及 RuntimeException的繼承關係圖)
https://docs.oracle.com/javase/tutorial/figures/essential/exceptions-throwable.gif

程式裏面,如果是遇到  Error/RuntimeException ,這一類的類別被Java歸類成 UnChecked Exception,代表  程式人員 不用特別寫程式進行處理。(*因為這一類的情形,如果真有發生,我們也來不及救了…  。如果JVM 出現OutMemoryError,我們也只能舉雙手投降了)。

至於像其它常見的,像 IOException,FileNotFoundException 等,
都分類為 Checked Exception,這些都是代表程式出錯時,JVM 會把 出錯的資訊 包裝成特定型態的物件,方便程式人員可以用程式來挽救出錯的情形,但不致於讓程式整個直接結束( Game Over)。

Java對所謂的 Checked Exception,在語法上有提供了幾個相關的關鍵字,
如 try / catch 以及 throws。接下來,我們先來看 用 try / catch的用法 ~

Round 1 :  通常程式需要 I/O,  connect Network, 或 Database 時,我們都會加上 try/catch
如下

上面的寫法,相信很容易在各種案子或各個地方看到~
基本上是ok的…javac 編譯也會過…我們稱 「有借有還」
就像 有 open動作,就該會有 close的動作。

不過,重點 不只要寫 close,還要在對的地方寫 ,寫錯地方 就等同於沒寫。
在上面第五行的地方,使用了 new  FileInputStream(file) ;
也許各位會想,就是 new FileInputStream的物件,為何會出錯呢 ?!
原因可能會有很多,舉簡單二、三個原因 來看,

  1. 檔案已經存在。代表無法再產生一個 FileInputStream來存取同一份檔案資源
  2. 寫入權限不足,比如說 一般user無法寫入系統的資料夾
  3. 硬碟空間已滿,這理由也很有可能會發生的喔 ~~~

那出錯之後呢 ?!  程式沒出錯的話,會一路從上往下執行,然後略過 catch。
但是如果一出錯,則程式流程會立即跳出 try { } 的區塊,然後進入 catch 的部份。
以上面來說的話,就是第五行出錯,會直接跳到第七行的 catch ,
而忽略最重要的第六行 close() .  (*進而可能會導致記憶體一直浪費,而沒有被回收,也就是所謂的 Memory Leak)

所以,該怎麼做比較對呢 ?!
Round 2 : 加上 finally  ,如下面的第九行

但是別忘了,即使在第九行之後,如果有呼叫 close() 時,也還是要再加一個 try/catch 才能真正的讓編譯器通過。 (*不然就是考慮 throws 用法 ,我們稱之謂 「轉身逃避」)

但…又有人會說,為何已經用 try / catch 了,而裏面還要再包一層呢 ~~
是不是 感覺有點多餘呢 ~?!

沒錯,就是有點多餘… 所以在 JDK 7 出來後,Oracle 原廠有加入個簡化的語法,
稱之為  try-with-resource,
語法:
try (  欲使用後關閉的物件  )  {
//  正常地 使用物件
}  catch (相對應的例外) {
// 例外發生時的處理,如 log, rollback 或 send email 等
}

範例如下 :

不知各位有沒有注意到,

  1. 沒有 close()
  2. 更沒有巢狀的 try / catch

try-with-resource的語法就是要讓開發人員更簡便的開發程式,
這麼好用的語法有沒有限制呢 ?!      答案是 有 !!!!

限制就是  欲使用後關閉的物件 必需直接或間接地  實作 AutoCloseable ,至於有哪些類別已經實作,請參考下圖

如果 使用的物件不符合期待(也就是直接/間接地 實作 AutoCloseable) ,
編譯器會”好心的提醒”開發人員…

是不是真的很實用呢 ?!


也許會想問說,如果是用 JDK6 甚至是 JDK5 的話呢 ?! 嗯~~ 沒問題的,就像下面這張~


(* 就別做夢了,趕快昇級 JDK 版本囉 ~  XD

後半部,我們會再接著介紹程式出錯之後, Exception 的建議處理方式 ~

參考資料(Reference)  :
https://dzone.com/articles/9-best-practices-to-handle-exceptions-in-java

Spring 註解 之 @Autowired

Spring 中的核心思為Ioc 與 DI 而DI 則是去實現 Ioc 的一個方式,而@Autowired就是Spring  2.5 後提供的一種方式,它可以對class成員變量、方法及構造函數進行標註,完成自動裝配的工作

一  .  @Autowired可使用的地方

1.class 的 setter 方法上面

2.class 的 建構函式上

3.成員變量上

二.  @Autowired的實作範例

首先我們先建立一個 Family.java 及 People.java

接著在Spring 的 xml 中加入 People<bean>配置People的value

接著我們在 Family.java 加上@Autowired

如此一來輸出的結果就會是我們在 xml 中配置 People >> name 的值 (  James )

我們只要將想賦予的值定義於xml中,透過@Autowired即可以直接將直注入,而不

須透過程式碼呼叫setter的方法

三. 當被配置的 bean 數量不為1 時,出現BeanCreationException,以下為解決方式

1.當被配置的 bean 數量不為0 時

我們將xml 中的 Family 註解掉,在執行程式時就會出現BeanCreationException

所以我們可以在@Autowired加上 (required=false),意思就是說在注入時Family不是找不到匹配Bean時也不出Exception

2.當被配置的 bean 數量大於1時,在執行程式時也會出現BeanCreationException

我們在xml 中再加入一個Family的bean,在執行程式時也會出現BeanCreationException

我們配置了兩個Family類型的bean,所以當我們對Family類型注入時,spring無法判斷要用哪一個,我們需要透過@Qualifier指定我們要注入的bean名稱,就可以解決此問題,而@Qualifier亦只能配合@Autowired使用