13.1 异常处理
Scala支持Java的异常处理语义,但是,它有着不同的语法。在Scala里,可以像Java那样抛出异常①:
①实例化时,可以忽略空的括号。
throw new WhatEverException
也可以像Java里那样放一个try
。不过,Scala并不强制捕获不关心的异常——即便是受控异常也不必捕获它。这样就无需在代码里添加不必要的catch
块——只要让那些不关心的异常沿着调用链传播上去即可。所以,举个例子,如果想调用Thread
的sleep()
,不用这样做:
// Java code
try {
Thread.sleep(1000);
}
catch(InterruptedException ex) {
// Losing sleep over what to do here?
}
只要写成这样即可:
Thread.sleep(1000)
Scala不会固执地强求不必要的try-catch
块了。
当然,对于某些可以为之做些什么的异常,我们肯定是要处理的——这才是catch
的意义所在。Scala的catch
语法有着很大的不同;我们可以使用模式匹配来处理异常,看个例子:
ScalaForTheJavaEyes/ExceptionHandling.scala
def taxFor(amount: Double) : String = {
if (amount < 0)
throw new IllegalArgumentException("Amount must be greater than zero")
if (amount < 0.1) throw new RuntimeException("Amount too small to be taxed")
if (amount > 1000000) throw new Exception("Amount too large...")
"Tax for $" + amount + " is $"+ amount * 0.08
}
for (amount <- List(100.0, 0.09, -2.0, 1000001.0)) {
try {
println(taxFor(amount))
}
catch {
case ex: IllegalArgumentException => println(ex.getMessage())
case ex: RuntimeException => {
// if you need a block of code to handle exception
println("Don't bother reporting..." + ex.getMessage())
}
}
}
上面的代码输出(带有部分栈追踪)如下:
Tax for $100.0 is $8.0
Don't bother reporting...Amount too small to be taxed
Amount must be greater than zero
java.lang.Exception: Amount too large...
at Main$$anon$1.taxFor((virtual file):9)
at Main$$anon$1$$anonfun$1.apply((virtual file):15)
at Main$$anon$1$$anonfun$1.apply((virtual file):13)
at scala.List.foreach(List.scala:841)
at Main$$anon$1.<init>((virtual file):13)
at Main$.main((virtual file):4)
...
taxFor()
方法根据输入抛出三种不同的异常。catch
块用case
语句处理两个异常。上面的输出展示了代码块如何处理这两个异常。第三个未处理的异常导致程序的终结,并打印出stack trace的细节。case语句的顺序很重要,请参考13.2节,“注意catch
的顺序”中介绍的内容。
Scala也支持finally
块——就像Java一样,无论try
块的代码是否抛出异常,它都会执行。
在上面的代码里,我们见识到了如何处理特定的异常。如果想捕获所有的异常,可以用_
(下划线)做case
条件,如下面例子所示:
ScalaForTheJavaEyes/CatchAll.scala
def taxFor(amount: Double) : String = {
if (amount < 0)
throw new IllegalArgumentException("Amount must be greater than zero")
if (amount < 0.1) throw new RuntimeException("Amount too small to be taxed")
if (amount > 1000000) throw new Exception("Amount too large...")
"Tax for $" + amount + " is $"+ amount * 0.08
}
for (amount <- List(100.0, 0.09, -2.0, 1000001.0)) {
try {
println(taxFor(amount))
}
catch {
case ex : IllegalArgumentException => println(ex.getMessage())
case _ => println("Something went wrong")
}
}
上面代码的输出如下。除有自己特殊catch
块的IllegalArgumentException
外,捕获所有(catchall)的case
捕获了的所有情况:
Tax for $100.0 is $8.0
Something went wrong
Amount must be greater than zero
Something went wrong
在Scala里,如同捕获受控异常是可选的一样,声明受控异常也是可选的。Scala并不需要声明抛出什么异常。参见11.4节“继承类”以了解与Java代码互操作相关的问题。