java将所有的错误封装为Throwable,Throwable下有两个子类:Error和Exception。scala本质上和java一样,都是运行在jvm上,同理scala也有和java类似的try catch异常处理机制,好处是scala有很多语法糖,在异常处理过程中可以节省开发者很大精力,下面看一下scala异常处理try与Try的使用:
try是scala内用作异常处理的写法,最常用的写法就是 try catch finally
def tryDemo(): Unit = {
// try
val label = try {
val value = redis.get("key")
if (noRes.contains(value)) {
"-1"
} else {
"1"
}
} catch {
case e: Exception => {
e.printStackTrace()
"-1"
}
} finally {
println("label处理完毕")
}
println(label)
}
这里catch到exception会进行异常处理,并返回默认值-1,Exception是java.lang.Exception,catch Exception会捕捉到如下Exception异常,但是捕捉不到error的情况:
java.lang.RuntimeException | 系统异常 |
java.lang.NullPointerException | 空指针异常 |
java.lang.ClassCastException | 类型转换异常 |
java.lang.IndexOutOfBoundsException | 下标越界 |
java.lang.ArrayIndexOutOfBoundsException | 数组下标越界 |
java.lang.StringIndexOutOfBoundsException | 字符串下标越界 |
java.lang.UnsupportedOperationException | 不支持的操作异常 |
java.lang.IllegalArgumentException | 非法参数异常 |
java.lang.NoSuchElementException | 方位未找到异常 |
java.lang.NumberFormatException | 数字格式异常 |
java.lang.AbstractMethodError | 抽象方法错误 |
java.lang.InterruptedException | 中断异常 |
error是java.lang.Error,如果需要捕捉非Exception类异常,则只需修改成如下写法:
case e: Error => {
xxx
}
一般在连接网络,初始化服务器失败时,会出现error的情况,一般情况下写bug的时候多为Exception
scala支持 _ 代表一切,常见的map(_.toString),foreach(println(_))等等,这里try catch支持这样的写法:
case _ => {
xxx
}
catch后加这个可以视为捕捉一切异常,error,exception都包括,偷懒情况下或者对异常情况不清楚可以这么写,不过代码可读性差,而且maven打包时会提醒打包的warning。
Try的机制有点类似option和Future,如果需要最终获取其中的值,需要通过.get获取,因为他们的执行都是不确定性的。
val numStr = "0"
val num = Try(numStr.toInt).get
println(num,num.getClass)
(0,int)
object Try {
/** Constructs a `Try` using the by-name parameter. This
* method will ensure any non-fatal exception is caught and a
* `Failure` object is returned.
*/
def apply[T](r: => T): Try[T] =
try Success(r) catch {
case NonFatal(e) => Failure(e)
}
}
r 就是我们执行的操作,T 是执行后返回的结果,针对上面的例子,r 是toInt,T 是Int,这里可以看到Try底层其实也是在使用try,Success是Try内的case class,也是Try的子类,类内提供了isSuccess,isFailure等方法,其返回值也是Try[T],e 是执行try时抛出的异常,从下面源码看到就是Throwable,包含了Error和Exception,当捕捉到异常时返回Failure,Failure和Success一样,也是Try的子类。
object NonFatal {
/**
* Returns true if the provided `Throwable` is to be considered non-fatal, or false if it is to be considered fatal
*/
def apply(t: Throwable): Boolean = t match {
// VirtualMachineError includes OutOfMemoryError and other fatal errors
case _: VirtualMachineError | _: ThreadDeath | _: InterruptedException | _: LinkageError | _: ControlThrowable => false
case _ => true
}
/**
* Returns Some(t) if NonFatal(t) == true, otherwise None
*/
def unapply(t: Throwable): Option[Throwable] = if (apply(t)) Some(t) else None
}
import scala.util.{Failure, Success, Try}
Try(num.toInt) match {
case Success(value) => println("Success")
case Failure(exception) => println("False")
case _ => println("unKnown")
}
通过match case模式匹配以及scala自带的Success类和Failure类,可以判断Try内逻辑是否执行正常,执行正常返回Success,执行错误返回Failure,这里.toInt是最常用的写法,里面也可以写复杂的逻辑,例如需要一些网络请求的任务,或者文件IO等等
Try(num.toInt) recover {
case e: Exception => 0
case e: Error => 1
case _ => 2
}
这里和try catch flinaly其实两种写法都可以达成上述效果,即异常捕捉与修复,当Try内抛出异常时,根据异常处理判断出现异常后的处理动作,如果执行结果状态为Success,则不会触发后续的recover。
针对上述case match和recover,Try也提供了更简便的写法供开发者使用,即getOrElse,如果Try内成功,返回T,否则返回默认值,类似map和jsonObject的getOrElse。
A.try catch
try {
num.toInt
} catch {
case e: Exception => 0
}
B.if else
if (num != null && num != "") {
num.toInt
} else {
0
}
C.Try
Try(num.toInt).getOrElse(0)