在之前的文章中我们提到了Option,scala中Option表示存在0或者1个元素,如果在处理异常的时候Option就会有很大的限制,因为Option如果返回None,那么我并不知道具体的异常到底是什么,这样scala引入了Either。

顾名思意,Either表示或者是这一个元素或者是那个元素。这样在异常处理的时候就非常有用了。

我们先看一下Either的定义:

sealed abstract class Either[+A, +B] extends Product with Serializable

它有两个子类Left和Right:

/** The left side of the disjoint union, as opposed to the [[scala.util.Right]] side.
*
* @author <a href="mailto:research@workingmouse.com">Tony Morris</a>, Workingmouse
*/
final case class Left[+A, +B](@deprecatedName('a, "2.12.0") value: A) extends Either[A, B] {
def isLeft = true
def isRight = false @deprecated("Use .value instead.", "2.12.0") def a: A = value
} /** The right side of the disjoint union, as opposed to the [[scala.util.Left]] side.
*
* @author <a href="mailto:research@workingmouse.com">Tony Morris</a>, Workingmouse
*/
final case class Right[+A, +B](@deprecatedName('b, "2.12.0") value: B) extends Either[A, B] {
def isLeft = false
def isRight = true @deprecated("Use .value instead.", "2.12.0") def b: B = value
}

我们通过这两个子类从两个可能的元素中选择一种。

Either 概念的产生时间早于Scala。很长时间以来它被认为是抛出异常的一种替代方案。

为了尊重历史习惯,当Either 用于表示错误标志或某一对象值时,Left 值用于表示错误标志,如:信息字符串或下层库抛出的异常;而正常返回时则使用Right 对象。很明显,Either 可以用于任何需要持有某一个或另一个对象的场景中,而这两个对象的类型可能不同。

我们看下怎么用Either的常规使用:


def positive(i: Int): Either[String,Int] =
if (i > 0) Right(i) else Left(s"nonpositive number $i") for {
i1 <- positive(5).right
i2 <- positive(10 * i1).right
i3 <- positive(25 * i2).right
i4 <- positive(2 * i3).right
} yield (i1 + i2 + i3 + i4)
// Returns: scala.util.Either[String,Int] = Right(3805) for {
i1 <- positive(5).right
i2 <- positive(-1 * i1).right // EPIC FAIL!
i3 <- positive(25 * i2).right
i4 <- positive(-2 * i3).right // EPIC FAIL!
} yield i1 + i2 + i3 + i4
// Returns: scala.util.Either[String,Int] = Left(nonpositive number -5)

再看一下Either怎么在代码中消除程序错误,将错误封装在Either中。

scala> def addInts(s1: String, s2: String): Int =
| s1.toInt + s2.toInt
addInts: (s1: String, s2: String)Int
scala> for {
| i <- 1 to 3
| j <- 1 to i
| } println(s"$i+$j = ${addInts(i.toString,j.toString)}")
1+1 = 2
2+1 = 3
2+2 = 4
3+1 = 4
3+2 = 5
204 | 第7 章
3+3 = 6
scala> addInts("0", "x")
java.lang.NumberFormatException: For input string: "x"

先看上面的例子,我们定义了一个addInts方法,接收两个String参数,并将其转换为Int。如果两个参数都是可以转换的字符串当然没问题,但是如果输入了一个无法转换的字符串就会报异常。

虽然异常有时候是好事情,但是异常会阻止程序的正常运行。我们看下怎么用Either来将其封装起来:

scala> def addInts2(s1: String, s2: String): Either[NumberFormatException,Int]=
| try {
| Right(s1.toInt + s2.toInt)
| } catch {
| case nfe: NumberFormatException => Left(nfe)
| }
addInts2: (s1: String, s2: String)Either[NumberFormatException,Int]
scala> println(addInts2("1", "2"))
Right(3)
scala> println(addInts2("1", "x"))
Left(java.lang.NumberFormatException: For input string: "x")
scala> println(addInts2("x", "2"))
Left(java.lang.NumberFormatException: For input string: "x")

按照上面的设计,Either封装好了异常,不会影响程序的正常运行,而且可以返回具体的错误信息,实在是一个不错的设计方式。

更多教程请参考 flydean的博客

Scala教程之:Either的更多相关文章

  1. scala教程之:可见性规则

    文章目录 public Protected private scoped private 和 scoped protected 和java很类似,scala也有自己的可见性规则,不同的是scala只有 ...

  2. Scala教程之:深入理解协变和逆变

    文章目录 函数的参数和返回值 可变类型的变异 在之前的文章中我们简单的介绍过scala中的协变和逆变,我们使用+ 来表示协变类型:使用-表示逆变类型:非转化类型不需要添加标记. 假如我们定义一个cla ...

  3. Scala教程之:可变和不变集合

    文章目录 mutable HashMap immutable HashMap 集合在程序中是非常有用的,只有用好集合才能真正感受到该语言的魅力.在scala中集合主要在三个包里面:scala.coll ...

  4. Scala教程之:Future和Promise

    文章目录 定义返回Future的方法 阻塞方式获取Future的值 非阻塞方式获取Future的值 Future链 flatmap VS map Future.sequence() VS Future ...

  5. Scala教程之:PartialFunction

    Scala中有一个很有用的traits叫PartialFunction,我看了下别人的翻译叫做偏函数,但是我觉得部分函数更加确切. 那么PartialFunction是做什么用的呢?简单点说Parti ...

  6. Scala教程之:Enumeration

    Enumeration应该算是程序语言里面比较通用的一个类型,在scala中也存在这样的类型, 我们看下Enumeration的定义: abstract class Enumeration (init ...

  7. Scala教程之:Option-Some-None

    文章目录 Option和Some Option和None Option和模式匹配 在java 8中,为了避免NullPointerException,引入了Option,在Scala中也有同样的用法. ...

  8. Scala教程之:scala的参数

    文章目录 默认参数值 命名参数 scala的参数有两大特点: 默认参数值 命名参数 默认参数值 在Scala中,可以给参数提供默认值,这样在调用的时候可以忽略这些具有默认值的参数. def log(m ...

  9. Scala教程之:可扩展的scala

    文章目录 隐式类 限制条件 字符串插值 s 字符串插值器 f 插值器 raw 插值器 自定义插值器 Scala是扩展的,Scala提供了一种独特的语言机制来实现这种功能: 隐式类: 允许给已有的类型添 ...

随机推荐

  1. PTA数据结构与算法题目集(中文) 7-31

    PTA数据结构与算法题目集(中文)  7-31 7-31 笛卡尔树 (25 分)   笛卡尔树是一种特殊的二叉树,其结点包含两个关键字K1和K2.首先笛卡尔树是关于K1的二叉搜索树,即结点左子树的所有 ...

  2. FastJson反序列化和构造函数之间的一点小秘密

    各位看官大家下午好,FastJson想必大家都很熟悉了,很常见的Json序列化工具.今天在下要和大家分享一波FastJson反序列化和构造函数之间的一点小秘密. 下面先进入大家都深恶痛绝的做题环节.哈 ...

  3. LeetCode | 力扣周赛C题 5370. 设计地铁系统

    请你实现一个类 UndergroundSystem ,它支持以下 3 种方法: checkIn(int id, string stationName, int t) 编号为 id 的乘客在 t 时刻进 ...

  4. psutil运维必会模块

    目录 psutil介绍 安装psutil 获取CPU信息 获取内存信息 获取磁盘信息 获取网络信息 获取进程信息 psutil介绍 用Python来编写脚本简化日常的运维工作是Python的一个重要用 ...

  5. webpack4.0(01.基础配置和初识)

    1.什么是webpack? 2.webpack可以做什莫? 代码转换.文件优化.代码分割.模块合并.自动刷新.代码校验.自动发布 3.我们要学习webpack的什么? 4.使用webpack 1.首先 ...

  6. IO操作与IO模型

    目录 一 .IO操作本质 二. IO模型 BIO – 阻塞模式I/O NIO – 非阻塞模式I/O IO Multiplexing - I/O多路复用模型 AIO – 异步I/O模型 三.同步I/O与 ...

  7. Linux网络安全篇,进入SELinux的世界(四)

    SELinux的策略与规则管理set 1.安装SELInux工具 yum install setools-console 2.基本的命令 seinfo [-Atrub] -A ===> 列出SE ...

  8. Flask 入门(七)

    flask操作数据库:建表: 承接上文: 修改main.py中的代码如下: #encoding:utf-8 from flask_sqlalchemy import SQLAlchemy from f ...

  9. spring-cloud feign的多参数传递方案

    查看原文 一.GET请求多参数URL 1.方法一(推荐) @FeignClient(“microservice-provider-user”) public interface UserFeignCl ...

  10. 2、使用断言(json assertion)

    1.假设现在有一个服务端的返回数据(需要测试的)为:HTTP/1.1 200 OK,要测试的响应字段勾选Response Headers,模式匹配规则选择Substring,把该响应断言命名为Http ...