Scala 优雅的异常处理之 try 与 Try

Scala 优雅的异常处理之 try 与 Try

java将所有的错误封装为Throwable,Throwable下有两个子类:Error和Exception。scala本质上和java一样,都是运行在jvm上,同理scala也有和java类似的try catch异常处理机制,好处是scala有很多语法糖,在异常处理过程中可以节省开发者很大精力,下面看一下scala异常处理try与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)
  }

Exception

这里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

error是java.lang.Error,如果需要捕捉非Exception类异常,则只需修改成如下写法:

      case e: Error => {
        xxx
      }

一般在连接网络,初始化服务器失败时,会出现error的情况,一般情况下写bug的时候多为Exception

Scala语法糖

scala支持 _ 代表一切,常见的map(_.toString),foreach(println(_))等等,这里try catch支持这样的写法:

      case _ => {
        xxx
      }

catch后加这个可以视为捕捉一切异常,error,exception都包括,偷懒情况下或者对异常情况不清楚可以这么写,不过代码可读性差,而且maven打包时会提醒打包的warning。

 

Try

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)
    }

}

就是我们执行的操作,是执行后返回的结果,针对上面的例子,toIntInt,这里可以看到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
}

模式匹配判断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)

 

你可能感兴趣的:(Scala,常用语法,scala,异常处理,try,Try)