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这种方式差。不得不说,虽然写起来比较啰嗦,但看着这个结构确实是一目了然。
但是不管如何,在我看来,函数式的错误处理依旧是很有趣的一个东西。如果合适的话,可以多在代码中尝试去使用:)
以上~
Scala函数式编程(五) 函数式的错误处理的更多相关文章
- swift之函数式编程(五)
文章内容来源于<Functional Programing in Swift>,详情请看原著 The Value of Immutability swift 对于控制值改变有一些机制.在这 ...
- Scala函数与函数式编程
函数是scala的重要组成部分, 本文将探讨scala中函数的应用. scala作为支持函数式编程的语言, scala可以将函数作为对象即所谓"函数是一等公民". 函数定义 sca ...
- scala函数式编程(二) scala基础语法介绍
上次我们介绍了函数式编程的好处,并使用scala写了一个小小的例子帮助大家理解,从这里开始我将真正开始介绍scala编程的一些内容. 这里会先重点介绍scala的一些语法.当然,这里是假设你有一些ja ...
- Scala 函数式编程思想
Spark 选择 Scala 作为开发语言 在 Spark 诞生之初,就有人诟病为什么 AMP 实验室选了一个如此小众的语言 - Scala,很多人还将原因归结为学院派的高冷,但后来事实证明,选择 S ...
- 大数据技术之_16_Scala学习_04_函数式编程-基础+面向对象编程-基础
第五章 函数式编程-基础5.1 函数式编程内容说明5.1.1 函数式编程内容5.1.2 函数式编程授课顺序5.2 函数式编程介绍5.2.1 几个概念的说明5.2.2 方法.函数.函数式编程和面向对象编 ...
- paip.函数式编程方法概述以及总结
paip.函数式编程方法概述以及总结 1 函数式编程:函数式风格..很多命令式语言里支持函数式编程风格 1.1 起源 (图灵机,Lisp机器, 神经网络计算机) 1.2 函 ...
- (转)现代C++函数式编程
本文转自:http://geek.csdn.net/news/detail/96636 现代C++函数式编程 C++ 函数式编程 pipeline 开发经验 柯里化 阅读2127 作者简 ...
- 拥抱函数式编程 I - 基本概念
函数编程与命令性编程 为支持使用纯函数方法解决问题,特此创建了函数编程范例. 函数编程是一种声明性编程形式.相比之下,大多数主流语言,包括面向对象的编程 (OOP) 语言(如 C#.Visual Ba ...
- javascript 函数式编程
编程范式 编程范式是一个由思考问题以及实现问题愿景的工具组成的框架.很多现代语言都是聚范式(或者说多重范式): 他们支持很多不同的编程范式,比如面向对象,元程序设计,泛函,面向过程,等等. 函数式编程 ...
- swift 之函数式编程(一)
1. 什么是函数式编程? 函数式编程是阿隆佐思想的在现实世界中的实现, 它将电脑运算视为数学上的函数计算,并且避免使用程序状态以及异变物件. 函数式编程的最重要基础是λ演算.而且λ演算的函數可以接受函 ...
随机推荐
- Redis-缓存穿透、缓存雪崩、缓存击穿、缓存一致性、并发竞争
缓存流程 在讲这五个问题之前,首先我们回顾下正常的缓存的使用流程 程序在处理请求时,会先从缓存中进行查询,如果缓存中没有对应的key,则会从数据库中查询,如果查询到结果,并将查询结果添加到缓存中去,反 ...
- Linux session(会话)
笔者在前文<Linux job control>中介绍了进程组(job)的概念以及常见的 job control 操作,本文接着介绍 session 的概念.本文中演示部分使用的环境为 u ...
- HTML中使用Vue+Dhtmlxgantt制作任务进度图
HTML中使用Vue+Dhtmlxgantt制作任务进度图 Dhtmlxgantt官网: https://dhtmlx.com/docs/products/dhtmlxGantt/ 参考文章 甘特图配 ...
- JDK 和JRE区别
JDK,开发java程序用的开发包,JDK里面有java的运行环境(JRE),包括client和server端的.需要配置环境变量.... JRE,运行java程序的环境,JVM,JRE里面只有cli ...
- Java 添加、修改、读取、复制、删除Excel批注
本文介绍通过Java程序来操作Excel批注的方法.操作内容包括批注添加(添加批注文本.背景色.字体.自适应等).修改.读取(文本.图片).复制.删除等. 工具:Free Spire.XLS for ...
- playbooks框架与子文件编写规范
Test Playbooks框架 详细目录testenv文件 主任务文件main.yml 任务入口文件deploy.yml Ansible连接playbooks需要添加ssh协议认证 ...
- 【聚类评价】Calinski-Harabaz(CH)
Calinski-Harabaz(CH) CH指标通过计算类中各点与类中心的距离平方和来度量类内的紧密度,通过计算各类中心点与数据集中心点距离平方和来度量数据集的分离度,CH指标由分离度与紧密度的比值 ...
- HttpApplication IHttpAsyncHandler, IHttpHandler, IComponent, IDisposable ps url System.Web.dll
// 摘要: // 定义 ASP.NET 应用程序中的所有应用程序对象共有的方法.属性和事件.此类是用户在 Global.asax 文件中所定义的应用程序的基类. [Toolb ...
- 团队第一次作业(软工C#造梦厂)
一.团队简介 a.团队名称:软工C#造梦厂 b.队员列表 姓名 学号 张旭(组长) 201731024123 周成杰 201731024136 邹扬锋 201731024134 赵俊安 2017310 ...
- 龙芯 3A4000 Fedora28 安装笔记
版权声明:原创文章,未经博主允许不得转载 3A4000用起来性能显然已经非常优秀,和朋友手上的3A3000相比有很大的提升(果然网上水分超多的什么测评看看呵呵就好).从零开始却用一半的核数和更低的制程 ...