拋出異常
異常的拋出看上去與Java如出一轍,首先建立一個異常對象而後用throw關鍵字拋出。但在scala裏,throw也是有結果類型的表達式。下面舉個有關結果類型的例子:java
package scalaTest object Test6 { def main(args:Array[String]):Unit = { println(fun(9)) } def fun(n:Int) = { if(n % 2 == 0) n/2 else throw new RuntimeException("n must be even") } }
執行結果:程序員
這段代碼的意思是,若是n是偶數,將打印n的一半。若是n不是偶數,那麼異常將被拋出。所以,不管怎麼說,把拋出的異常看成任何類型的值都是安全的。任何使用經throw返回值的嘗試都不會起做用,所以這樣作不會有害處。
從技術角度上來講,拋出異常的類型是Nothing。儘管throw不實際產生任何值,你仍是能夠把它看成表達式。這種小技巧或許看上去很怪異,但像在上面這樣的例子裏卻經常頗有用。If的一個分支計算值,另外一個拋出異常並獲得Nothing。整個if表達式的類型就是那個實際計算值的分支的類型(Nothing類型將在之後會講到)。數據庫
捕獲異常安全
package scalaTest import java.io.FileReader import java.io.FileNotFoundException import java.io.IOException object Test6 { def main(args:Array[String]):Unit = { try { val f = new FileReader("input.txt") //使用並關閉文件,省略.................... }catch{ case ex:FileNotFoundException => { println("文件沒有找到!") } case ex:IOException => println("IO異常") } } }
上面演示了捕獲異常的語法。選擇catch子句這種語法的緣由是爲了與scala很重要的部分:模式匹配保持一致,模式匹配是一種很強大的特徵(咱們在後面章節中會講到)。
這個try-catch表達式的處理方式與其餘語言中的異常處理一致。首先執行程序體,若是拋出異常,則依次嘗試每一個catch子句。本例中,若是異常是FileNotFoundException,那麼第一個子句將被執行。若是是IOException類型,第二個子句將被執行。若是都不是,那麼try-catch將終結把異常向上拋出去。
注意:
你將很快發現與java的差異是scala裏不須要捕獲檢查異常,或把它們聲明在throws子句中。若是願意,你能夠用@throws註解聲明throws子句,但這不是必須的(這個後面會講到)。函數
finally子句
若是想讓某些代碼不管方法如何停止都要執行的話,能夠把表達式放在finally子句裏。如例:測試
package scalaTest import java.io.FileReader import java.io.FileNotFoundException import java.io.IOException object Test6{ def main(args:Array[String]):Unit = { try{ val f = new FileReader("input.txt") //省略....... }catch{ case ex:FileNotFoundException => { println("文件沒有找到") } case ex:IOException => println("IO異常") }finally{ println("必須執行的語句") } } }
或者url
package scalaTest import java.io.FileReader import java.io.FileNotFoundException import java.io.IOException object Test6{ def main(args:Array[String]):Unit = { try{ val f = new FileReader("./.classpath") println(f.getEncoding()) //省略........... }finally{ println("必須執行的語句") } } }
注意:通常確保內存資源,如:文件、套接字、數據庫鏈接等被關閉的慣例方式是在finally中進行處理,這跟在java中是同樣的。Scala裏還可使用另外一種被稱爲出借模式(loan pattern)的技巧更簡潔地達到一樣的目的(這個出借模式後面再講)。spa
生成值
和其餘大多數scala控制結構同樣,try-catch-finally也產生值。如例:.net
package scalaTest import java.net.URL import java.net.MalformedURLException object Test6 { def main(args:Array[String]):Unit = { println(urlFor("ddd")) } def urlFor(path:String) = { try{ new URL(path) }catch{ case e:MalformedURLException => new URL("http://www.scala-lang.org") } } }
結果:scala
上例演示瞭如未嘗試拆分URL,但若是URL格式錯誤就使用默認值。也就是,若是沒有異常拋出,則對應於try子句;若是拋出異常並被捕獲,則對應於相應的catch子句。若是異常被拋出但沒被捕獲,表達式就沒有返回值。
由finally子句計算獲得的值,即便有也會被拋棄。一般finally子句作一些諸如關閉文件之類的清理工做,它們不該該修改主函數體或catch子句中計算的值。
Scala的行爲與java的差異僅在於java的try-finally不產生值。在java裏,若是finally子句包含返回語句,或拋出一個異常,這個返回值或異常將「凌駕」於任何以前在try代碼塊或某個catch子句裏產生的值或異常之上。
咱們來測試一下,scala的finally中定義返回語句的狀況,以下例:
package scalaTest object Test6{ def main(args:Array[String]):Unit = { println(f) } def f() = { try{1}finally{2} } }
結果:
咱們再來看看另外一個很特別的例子:
package scalaTest object Test6 { def main(args:Array[String]):Unit = { println(f) } def f():Int = { try{return 1}finally{return 2} } }
(注: scala中使用return進行返回值的時候,方法上必定要註明返回類型!!!),咱們再來看看結果(很震驚!!!!!!至關震驚!!!!):
這兩個例子足以令大多數程序員震驚!!!所以一般最好仍是避免用finally子句返回值,而是把它理解爲確保某些操做發生的途徑,如關閉打開文件。