IT教程 ·

Scala函数式编程(五) 函数式的错误处理

qt creator源码全方面分析(2-10-2)

前情提纲

Scala函数式编程指南(一) 函数式头脑引见

scala函数式编程(二) scala基本语法引见

Scala函数式编程(三) scala鸠合和函数

Scala函数式编程(四)函数式的数据构造 上

Scala函数式编程(四)函数式的数据构造 下

1.面向对象的毛病处置惩罚

在引见scala的函数式的毛病处置惩罚之前,我们要先来引见一下其他状况下的毛病处置惩罚体式格局。

以java为例,罕见的毛病处置惩罚体式格局不外乎两种,一种是实时捕捉到异常,然后就地举行处置惩罚。

try{
    ... 
}catch(Exception e){
    ...
    
}finally{
    
}

另一种则是将异常抛出,层层捕捉,然后在最上层对异常举行一致处置惩罚,这类通常是在大型项目的时刻会运用。

这两种毛病处置惩罚的要领是,在我们一样平常的编程中,已足以应对多种状况。

但在函数式编程中却不可,函数式编程寻求的是无副作用的代码,无副作用最直接的运用就是可以放心得并发运转,而抛出异常却会发生副作用。

try catch处置惩罚的弊病,在并发编程中实在有较为显著的表现。

以spark为例,假如spark主节点master讯问worker节点的健康状况,当worker节点出现异常时,明显让master节点来捕捉并处置惩罚这个异常,有点不符合情理。

更合理的处置惩罚,应当是让master接收到一个示意毛病状况的音讯,然后再决议接下来怎样处置惩罚。而worker的异常就让worker本身去处理吧。

而在scala中,有一种特定的范例,它用来示意大概致使异常的一个盘算历程,这就是Try。

2.从Option到Try

前面有引见过Option,相干引见可以看这里Scala函数式编程(三) scala鸠合和函数。

这里简朴引见一下Option。

Option呢,实在就是薛定谔的值,内里大概有值,也大概没有值。只要到要看的时刻,才会晓得Option内里究竟有无值。

Option全程叫Option[A],示意Option内里存的是A范例的值,这个A可以是Int,String,等等。我们可以经由过程get这个api来猎取Option[A]内里的值,当不存在时,get会返回None。

可以经由过程isEmpty,来确认Option内里究竟是不是是有值。也可以经由过程getOrElse来指定没有值的时刻要返回什么值。

Try[A]和Option相似,都是示意一个大概有也大概没有的东西。现实对应过来, Try[A]就示意一个大概胜利也可以失利的盘算,假如胜利,则返回A范例,假如失利,则返回Throwable。

先最在交互式环境中直寓目一下怎样运用吧:

scala> import scala.util.Try
import scala.util.Try

scala> Try(1+1)
res15: scala.util.Try[Int] = Success(2)

scala> Try(1/0)
res16: scala.util.Try[Int] = Failure(java.lang.ArithmeticException: / by zero)

可以完成这个功用,重要是由于Try的两个子范例:

  • Success[A]:代表胜利的盘算。
  • 封装了 Throwable 的 Failure[A]:代表出了错的盘算。

是不是是和Option很像呢?也是薛定谔的毛病,在没打开来看之前,Try内里多是胜利的,也多是失利的。

一样可以经由过程isSuccess和isFailure来确认究竟这个Try是胜利照样失利。

假如一个函数中有一个盘算大概会失足,那末我们就可以直让函数返回Try,然后对胜利照样毛病,就全交由调用者来举行处置惩罚,比方上面说到的,Spark的谁人例子。

3.Try的运用

上面开端引见了Try的寄义和用法,接下来就来看看Try这个东西,另有哪些通例的用法吧。

3.1 map

map是scala内里异常经常使用的一种操纵,Try内里也有!

对Try运用Map的话,会将一个是Success[A]的Try[A]映射到Try[B]会获得Success[B]。假如它是Failure[A],就会获得Failure[B],而且包括的异常和Failure[A]一样。

看看例子吧:

//新建一个Try,注重,这里是Try[Int]
scala> val tryMap = Try(1+1)
tryMap: scala.util.Try[Int] = Success(2)

//运用Map,让它变成Try[String]了
scala> tryMap.map(_.toString)
res46: scala.util.Try[String] = Success(2)

//新建一个会失利的Try[Int]
scala> val tryMapFail = Try(1 / 0)
tryMapFail: scala.util.Try[Int] = Failure(java.lang.ArithmeticException: / by zero)

//转换成Try[String]了,但Failure的异常范例稳定
scala> tryMapFail.map(_.toString)
res47: scala.util.Try[String] = Failure(java.lang.ArithmeticException: / by zero)

Try不止支撑map,还支撑for,flatMap,filter等通例操纵,从这个角度看,Try反而更像一种数据构造。

3.2 毛病时刻的默认值getOrElse

和Option一样,Try还很轻易得供应了getOrElse这个要领。当你想为失利的时刻做些什么的时刻就可以用这个api。

这个我举个简朴的例子,将字符串转换为Int范例。在字符串转Int范例的时刻呢,大概会碰到一些不符合范例的数据。这时刻你就不得不斟酌数据是不是可以平安得转换成Int,但有了Try,可以很轻易得用getOrElse,要领。

当碰到不能转成Int的字符串,授与一个默认值即可。

scala> import scala.util.Try
import scala.util.Try

scala> "12".toInt
res17: Int = 12

scala> "asd".toInt
java.lang.NumberFormatException: For input string: "asd"
  at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
  at java.lang.Integer.parseInt(Integer.java:580)
  at java.lang.Integer.parseInt(Integer.java:615)
  at scala.collection.immutable.StringLike$class.toInt(StringLike.scala:272)
  at scala.collection.immutable.StringOps.toInt(StringOps.scala:29)
  ... 32 elided

scala> Try("asd".toInt).getOrElse(-1)
res19: Int = -1

但这里照样得多说一句,这类做法会疏忽掉底本应当抛出的毛病,你须要明白晓得本身确实是要疏忽掉这个毛病才如许用

不然大概由于设置的默认值致使出现问题,而毫无眉目,由于程序并没有报任何毛病!!

3.3 形式婚配

我们可以没必要如java的try catch那般去处置惩罚Try失利时返回的异常。由于我们有scala的形式婚配。

不得不说,形式婚配真的是很壮大的一个言语特征。前面不是说到嘛,Try有两个子类,Success和Failure,胜利时刻返回Success,失利时返回Failure。

所以我们就可以如许做:

import scala.util.Success
import scala.util.Failure
val operation = Try(1 / 0)
operation match {
  case Success(num) => println(num)
  case Failure(ex) => println(s"Problem is ${ex.getMessage}")
}

由于除数为0,所以这个Try是失利的,所以这里会输出:Problem is / by zero

scala壮大的形式婚配,可以轻易得让我们处置惩罚毛病和非毛病的状况。

4. 小结

Scala 的毛病处置惩罚和其他范式的编程言语有很大的差别。 Try 范例可以让你将大概会失足的盘算封装在一个容器里,并文雅的去处置惩罚盘算获得的值。 而且可以像操纵鸠合和 Option 那样一致的去操纵 Try。

同时Try[A]也支撑罕见数据构造中的操纵,诸如Map,Filter等通例的api都支撑。

Try这类毛病处置惩罚的体式格局,显著更适用于函数式的状况,也就是说更适合在并发编程的时刻运用。

但在我看来,Try也是有一些不好的处所,比方说在代码可读性方面就比try catch这类体式格局差。不得不说,虽然写起来比较烦琐,但看着这个构造确实是一览无余。

然则不论怎样,在我看来,函数式的毛病处置惩罚依旧是很风趣的一个东西。假如适宜的话,可以多在代码中尝试去运用:)

以上~

One Stage目标检测

参与评论