2016年4月14日 星期四

[Scala 小學堂] Scala Gossic : 起步走 - 內建控制結構 (try 運算式)

轉載自 這裡 
前言 : 
Scala 是一個可直譯、編譯、靜態、運行於 JVM 之上、可與 Java 互操作、融合物件導向編程特性與函式編程風格的程式語言. 從一些簡單的語法開始,了解 Scala 的許多特性,所以就算是起步走,東西也夠多了. 簡單的小程式可以使用 scala 指令,編譯的事就交給 scalac,編譯想快點就用 fsc. (Scala 官網), 運算式有傳回值,迴圈沒有,對了!Scala 沒有 break 與 continue. 

try 運算式 : 
如果你撰寫了這段程式 : 
  1. val filename = args(0)  
使用者如果沒有提供命令列引數,則 args 的長度會是0,存取索引 0 就會發生超出陣列索引範圍的錯誤,在 Scala 中,會丟出 java.lang.ArrayIndexOutOfBoundsException。你可以使用 isEmpty 來測試 args 是否為空: 
  1. if(args.isEmpty)  
  2.         throw new IllegalArgumentException("Please provide arguments")  
  3. val filename = args(0)  
  4. // Continue app  
另一個方式是使用 try...catch 語句,在使用者沒有提供引數時,於 catch 中捕捉例外並顯示錯誤訊息 : 
- Try2.scala 代碼 : 
  1. try{  
  2.         val filename = args(0)  
  3.         // Continue app  
  4. }catch{  
  5.         case ex: ArrayIndexOutOfBoundsException => println("Please provide arguments!")  
  6. }  
程式會嘗試取得 args(0),如果丟出例外,而在 catch 中有撰寫對應的 case 比對,則會執行對應的處理程式。如果有多個例外類似要比對,則可以撰寫多個 case,如果最後有一定得處理的程式,則可以撰寫 finally 區塊,例如 : 
- Try3.scala 代碼 :
  1. import java.io._  
  2. try{  
  3.         val reader = new FileReader(args(0))  
  4.         try{  
  5.                 //Do some operation  
  6.         } catch {  
  7.                 case ex: IOException => println("IO Error!")  
  8.         } finally {  
  9.                 reader.close()  
  10.         }  
  11. catch {  
  12.         case ex: ArrayIndexOutOfBoundsException => println("Please provide arguments")  
  13.         case ex: FileNotFoundException => println("File not found: "+args(0))  
  14. }  

在 Scala 中,並不要求你得處理受檢例外(Checked Exception)(參考 Java 的 例外的繼承架構), 你只需針對感興趣或有能力處理的例外加以捕捉並處理即可,如果在例外發生的當時情境下無力處理,你什麼事都不用作(不用寫 try...catch 也不用在 函式或方法上用 throws 宣告),將處理留給後續的呼叫者來善後在 Java 中,受檢例外是由編譯器進行檢查,Scala 編譯器不檢查受檢例外,事實上,Scala 也沒有 throws 關鍵字。如果你要讓某個方法在編譯後產生的位元碼中,有 Java 中 throws 宣告,以便給 Java 程式使用時可以得到 受檢例外檢查機制,則可以使用 @throws 標注,標注的使用之後還會說明). 在Scala 中,try...catch...finally 是運算式,所以會有運算結果,例如你可以撰寫這樣的程式碼 : 
- Try4.scala 代碼 :
  1. val filename =  
  2. try {  
  3.         args(0)  
  4. catch {  
  5.         case ex: ArrayIndexOutOfBoundsException => "default.properties"  
  6. }  
  7. println("Filename: "+filename)  

如 果有提供命令列引數,則將 filename 設定為所提供的值,否則就是設定為 default.properties。你也可以在 finally 中提供傳回 值,不過並不鼓勵,因為 finally 中基本上是用來關閉、釋放某些資源或作些善後動作。如果你要在 finally 中提供傳回值,要注意一下以下兩個程式片段的不同 : 
  1. def doSome = try { 1 } finally { 2 }  
如果你呼叫 doSome(),則以上程式片段會傳回 try 區塊中的1,但如果是 : 
  1. def doSome: Int = try { return 1 } finally { return 2 }  
因為你明確地使用 return,這個程式片段會傳回 2(這個行為與 Java 是相同的)。如先前所提到的,在finally中並不建議有傳回值,而僅用於關閉、釋放資源或作些善後動作明確地使用 return 在 Scala 中也是不鼓勵的,因為容易破壞程式的結構,在 Scala 中使用 return 就無法使用類 型推斷,像以上定義函式時,就得明確定義函式的傳回值型態,另外,return 在 Scala 中只能用於函式之中). 在Scala 中處理例外,要注意一下例外比對的順序,例如 : 
- Try5.scala 代碼 :
  1. val filename =  
  2. try{  
  3.         args(0)  
  4. catch {  
  5.         case ex: Exception => "Exception"//Do some operation  
  6.         case ex: ArrayIndexOutOfBoundsException => "BoundsException"//Do some operation  
  7. }  
  8. println("Filename= "+filename)  

由於 Exception 是 ArrayIndexOutOfBoundsException 的父類別,所以這個程式片段,只會符到到第一個 Exception,第二個 ArrayIndexOutOfBoundsException 永遠不會被比對到,Scala不會提出警訊(Java的編譯器會對這部份作檢查),程式會照常執行. 

Supplement 
Tutorialspoint - Scala Exception Handling
起步走 - 內建控制結構 (if 運算式) 
起步走 - 內建控制結構 (for 運算式) 
起步走 - 內建控制結構 (while 迴圈) 
起步走 - 內建控制結構 (match 運算式) 
起步走 - 內建控制結構 (try 運算式)

沒有留言:

張貼留言

[Git 文章收集] Differences between git merge and git rebase

Source From  Here Preface Merging and rebasing are the two most popular way to applying changes from one branch into another one. They bot...