抛出异常
异常的抛出看上去与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子句返回值,而是把它理解为确保某些操做发生的途径,如关闭打开文件。