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的情况:

异常API说明
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)
    }
}

(这里使用的传名参数 因为没有参数可以直接写函数体)
r 就是我们执行的操作,T 是执行后返回的结果,针对上面的例子,rnumStr.toIntTInt,这里可以看到Try底层其实也是在使用try,Success是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(throwable) => 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

 val t = try {
      num.toInt
    } catch {
      case e: Exception => 0
    } 

B .Try

val t = Try(num.toInt).getOrElse(0)

使用Try[T] 处理Future计算
有时候为了简洁,用户会希望在同一个回调中同时处理成功和失败的情况。要实现这一点,需要使用Try[T]类型,此类型和Option[T]类型非常类似。
如果熟悉Scala串行编程,读者应该知道 Option[T]类型用来存储一个类型为 T 的对象或空值,
即Option[T]类型的值既可以是类型Some[T],也可以是None,即什么也没有。
这两者是通过模式匹配来区分的。Option类型是另一种使用null值的方式,在Java中会经常这样做,
但是,Option[T]无法在它的None子类型中存储失败信息,用户无法从None子类型中获得异常的任何信息,这时Try[T]就派上用场了。

Try[T]类型有两种实现,
一种是Success[T]类型,它保存了计算成功后的结果;
另一种是Failure[T]类型,它保存了计算失败时抛出的Throwable对象。
然后,可以用模式匹配来确定Try[T]对象到底是哪一种。

Try[T]对象是在同步场合下使用的不可变对象,在创建时就将值或异常保存下来了,这和Future对象不一样。相比Future,Try[T]更像容器

def getUrlSpec(): Future[List[String]] = Future {
    val url = "http://www.w3.org/Addressing/URL/url-spec.txt"
    val f = Source.fromURL(url)
    try f.getLines.toList finally f.close()
  }
 //在大部分情况下,模式匹配使用的是Try值。当调用onComplete回调函数时,
 //会为它提供匹配Success值或Failure值的部分函数。
 urlSpec onComplete {
   case Success(txt) => log(find(txt))
   case Failure(err) => log(s"exception occurred - $err")
 }
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Scala中,try-catch语句用于捕获和处理异常。在try块中,我们可以编写可能会抛出异常的代码。如果异常被抛出,catch块将捕获并处理异常。在catch块中,我们可以定义异常类型,并指定对不同类型的异常应该执行的代码。如果没有异常被抛出,catch块将被忽略。 在给定的代码示例中,try-catch语句用于捕获异常并执行相应的代码。在第一个示例中,try块中的代码尝试将字符串转换为整数。如果出现异常(例如,字符串不能被转换为整数),catch块将捕获该异常,并返回0。 第二个示例中的try-catch语句用于捕获ArrayIndexOutOfBoundsException(数组越界)异常。如果出现此异常,catch块将捕获该异常,并打印一条消息。然后,程序将继续执行。 第三个示例中的try-catch语句用于捕获ArithmeticException(算术异常)异常。如果出现此异常(例如,除以零),catch块将捕获该异常,并打印一条消息。然后,程序将继续执行。 总结来说,在Scala中,我们可以使用try-catch语句来处理可能引发的异常,并为每种异常类型指定不同的处理方式。这样可以使我们的代码更加健壮,并能够及时处理异常情况。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [Scala 优雅异常处理tryTry](https://blog.csdn.net/BIT_666/article/details/107640484)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* *3* [Scala try-catch 语句](https://blog.csdn.net/love284969214/article/details/82731774)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值