语法处理上和Java类似,但是又不尽相同

Java异常处理

  1. object ExceptionDemo {
  2. def main(args: Array[String]): Unit = {
  3. try {
  4. val a = 10
  5. val b = 0
  6. val c = a / b
  7. } catch {
  8. case e: ArithmeticException =>
  9. //catch时,需要将范围小的写到前面
  10. e.printStackTrace()
  11. case e: Exception =>
  12. e.printStackTrace()
  13. } finally System.out.println("finally")
  14. }
  15. }

注意事项
(1)Java语言按照try—catch—finally的方式来处理异常
(2)不管有没有异常捕获,都会执行finally,因此通常可以在finally代码块中释放资源
(3)可以有多个catch,分别捕获对应的异常,这时需要把范围小的异常类写在前面,把范围大的异常类写在后面,否则编译错误

Scala异常处理

  1. def main(args: Array[String]): Unit = {
  2. try {
  3. var n= 10 / 0
  4. }catch {
  5. case ex: ArithmeticException=>{
  6. //发生算术异常
  7. println("发生算术异常")
  8. }
  9. case ex: Exception=>{
  10. //对异常处理
  11. println("发生了异常1")
  12. println("发生了异常2")
  13. }
  14. }finally {
  15. println("finally")
  16. }
  17. }

(1)我们将可疑代码封装在try块中,在try块之后使用了一个catch处理程序来捕获异常。如果发生任何异常,catch处理程序将处理它,程序将不会异常终止

(2)Scala的异常的工作机制和Java一样,但是Scala没有“checked(编译期)”异常,即Scala没有编译异常这个概念,异常都是在运行的时候捕获处理

(3)异常捕捉的机制与其他语言中一样,如果有异常发生,catch子句是按次序捕捉的。因此,在catch子句中,越具体的异常越要靠前,越普遍的异常越靠后,如果把越普遍的异常写在前,把具体的异常写在后,在Scala中也不会报错,但这样是非常不好的编程风格

(4)finally子句用于执行不管是正常处理还是有异常发生时都需要执行的步骤,一般用于对象的清理工作,这点和Java一样

(5)用throw关键字,抛出一个异常对象,所有异常都是Throwable的子类型,throw表达式是有类型的,就是Nothing,因为Nothing是所有类型的子类型,所以throw表达式可以用在需要类型的地方

  1. def test():Nothing = {
  2. throw new Exception("不对")
  3. }

(6)java提供了throws关键字来声明异常,可以使用方法定义声明异常,它向调用者函数提供了此方法可能引发此异常的信息,它有助于调用函数处理并将该代码包含在try-catch块中,以避免程序异常终止,在Scala中,可以使用throws注解来声明异常

  1. @throws(classOf[NumberFormatException])
  2. def f11()={
  3. "abc".toInt
  4. }

Try

Try的机制有点类似option和Future,如果需要最终获取其中的值,需要通过.get获取,因为他们的执行都是不确定性的。
image.png

基本写法

  1. val numStr = "0"
  2. val num = Try(numStr.toInt).get
  3. println(num,num.getClass) // (0,int)

源码

  1. object Try {
  2. /** Constructs a `Try` using the by-name parameter. This
  3. * method will ensure any non-fatal exception is caught and a
  4. * `Failure` object is returned.
  5. */
  6. def apply[T](r: => T): Try[T] =
  7. try Success(r) catch {
  8. case NonFatal(e) => Failure(e)
  9. }
  10. }

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的子类。

判断Try内是否成功执行 match

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等等

恢复模式匹配并做异常处理 recover

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)