Scala中如何优雅的处理Null
前言
如果在scala代码还在使用id! = null,可能会被有的人嘲笑,都什么年代了,竟然还有这样的写法,NullPointerException见少了吧?
不过,据统计:
Spark 源代码使用了 821 次 Option 关键字,但它有直接使用如if (id != null)。
Spark 采用混合方式,大部分情况下使用 Option,但个别时候出于性能(这里主要是为了给使用者返回提示信息)原因才使用了null。
一个很好的习惯是当有方法返回值可能为null的时候,使用Option来代替。
什么是Option
标准类库中Option类型用样例类来表示那种可能存在、也可能不存在的值。
Option的有两个子类,Some 和 None,Some包装了某个值,如Some(“Jack”),而None表示没有值。
有的小伙伴看到依然云里雾里的,因此直接上一个简单的例子,来感受一下这个Option究竟是什么东西:
煮个栗子
这里写了一个把字符串转为数值的方法,输入的是字符串,输出的这里注意一下,并不是直接输出Int,而且一个泛型为Int的Option
def toInt(in: String): Option[Int] = {try {Some(Integer.parseInt(in.trim))} catch {case e: NumberFormatException => None}
}
如何使用这个函数:
toInt("s") match {case Some(i) => println(i)case None => println("您输入的字符串无法转为数字")
}
简单的总结一下这个Option的使用,其实就是把你原本要返回的类型,直接返回泛型为该类型的Option,然后写正常返回值的时候返回Some,异常的时候返回None即可。而调用方法的时候,需要用到match case分别做处理。
有人看到这里可能会抱怨:一个简单的null判断,写了这么一大堆,还不如java中的直接用i!=null来判断简单粗暴呢。
但是如果这个toInt函数是别人写的,你是个使用者,你一定会遇到如下问题:
- 你没有读API文档,根本不知道toInt可能会返回一个null,并且可能你写的代码会抛出NullPointerException
- 你读了API文档,并且也有很多使用这个函数的经验,知道它可能会返回null,因此你肯定会写如下代码来处理可能出现的空指针异常
Integer i = toInt(someString);
if (i == null) {System.out.println("您输入的字符串无法转为数字");
} else {System.out.println(i);
}
该代码并不比 Scala的Option和match方法差,但你确实必须阅读API文档才能知道必须得这样处理。
- 当然还可以通过抛出NumberFormatException来处理null或者其他一些异常情况
Option的好处不仅如此
比如想统计下面list中的总和,这些字符串有的可以转为Int,有的不可以
val bag = List("1", "2", "foo", "3", "bar")
要实现这个需求,感觉要写很多代码才能实现,其实在scala中只要一行代码就可以实现:
val sum = bag.flatMap(toInt).sum
为什么可以这么简单的就实现:
我们的toInt方法返回的是Some[Int]或None,而flatMap知道如何处理这些值,所以实现起来就小菜一碟了,而且还很容易阅读和理解。
这就是使用Option/Some/None 模式真正牛叉的地方了
简单的总结java null 与 scala Option
如果你用别人写的java方法,那么一般需要阅读API文档,或者是使用后抛出了NullPointException后,查文档和资料发现,需要处理这个空指针异常。那么scala Option我们在使用函数的时候,可以看到返回值是个Option[Int](直接在IDE中就能看到返回值类型,不需要去阅读该函数的API文档),说明开发这个函数的人一定用了Option/Some/None这一套组合拳,因此就知道用match case来解决了。
在我看来,其实从写代码的角度来看代码量并没有减少,优点有两:
- 更具有可读性,
- 避免在使用函数的时候,出现空指针异常
Option的缺点
有的人会说,你前言中都说了连spark源码都不是一律采用Option来处理null值,你既然上面吹的神乎其神的,人家干嘛不全部用Option?
这里就得说一下Option的一个缺点:
无法说出某件事失败的原因(也就是为什么你得到了一个None而不是一个Some),因为根本就看不到错误异常信息
对此scala 的解决方案是使用Either Left 和 Right来处理异常信息
Either Left Right简介与使用
Either其实用起来和Option很像,不同的是Either可以返回一个字符串来描述发生的问题。
Either 和Option的比较:
Either 就像 Option
Right 就像 Some
Left 就像 None (不过它是写出发生问题的原因)
还是搞一段代码来解释
/*** 这里写个简单的方法来演示,如何写一个返回值为Either的方法* 以及Either中Left和Right的用法*/
def divideXByY(x: Int, y: Int): Either[String, Int] = {if (y == 0) Left("零不能作为除数")else Right(x / y)
}// 使用 Either, Left, and Right的几种不同方式
println(divideXByY(1, 0))
println(divideXByY(1, 1))
divideXByY(1, 0) match {case Left(s) => println("Answer: " + s)case Right(i) => println("Answer: " + i)
}
上面divideXByY方法返回的是一个Either[String, Int],这个泛型String就是Left方法中传入的数据类型,而Int就是Right方法传入的数据类型。
通过上面的例子,会发现这一套东西和Option/Some/None使用起来很像,唯一不同的是,Either将出错的信息可以传回,使用者可以看到异常信息。我们看看官网是怎么说的:
Represents a value of one of two possible types (a disjoint union.) Instances of Either are either an instance of Left or Right.
A common use of Either is as an alternative to Option for dealing with possible missing values. In this usage,
scala.None is replaced with a Left which can contain useful information. Right takes the place of Some.
Convention dictates that Left is used for failure and Right is used for success.
说白了就是我上面写的,如果要返回错误信息给使用者,就用Either。不过根据我经验,一般这样的场景不算多。因此最长用的还是Option。
Scala中如何优雅的处理Null相关推荐
- Scala中Unit、Nothing和Null之间的区别概述
在Scala中,Unit.Nothing和Null是三个比较特殊的数据类型,三者之间的区别如下: Unit 类似于Java中的void,表示没有返回值,用于不返回任何结果的方法的结果类型. 只有一个实 ...
- scala中使用Option、Some、None,避免使用null
避免null使用 大多数语言都有一个特殊的关键字或者对象来表示一个对象引用的是"无",在Java,它是null.在Java 里,null 是一个关键字,不是一个对象,所以对它调用任 ...
- Scala中的None,Nothing,Null,Nil
在scala中这四个类型名称很类似,作用确实完全不同的. None是一个object,是Option的子类型,定义如下 case object None extends Option[Nothing] ...
- Scala系列-4、scala中特质、柯里化、闭包等
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明. 传送门:大数据系列文章目录 目录 scala中特质 特质作为接口使用 特质中放置非抽象的成员 ...
- Akka 系列(五):Java 和 Scala 中的 Future
随着CPU的核数的增加,异步编程模型在并发领域中的得到了越来越多的应用,由于Scala是一门函数式语言,天然的支持异步编程模型,今天主要来看一下Java和Scala中的Futrue,带你走入异步编程的 ...
- Scala 中的函数式编程基础
主要来自 Scala 语言发明人 Martin Odersky 教授的 Coursera 课程 <Functional Programming Principles in Scala>. ...
- completablefuture 线程池_SpringBoot中如何优雅的使用多线程
本文带你快速了解@Async注解的用法,包括异步方法无返回值.有返回值,最后总结了@Async注解失效的几个坑. 在 SpringBoot 应用中,经常会遇到在一个接口中,同时做事情1,事情2,事情3 ...
- 13.10 Scala中使用JSON.toJSONString报错:ambiguous reference to overloaded definition
13.10 Scala中使用JSON.toJSONString报错:ambiguous reference to overloaded definition 问题描述: [ERROR] /Users/ ...
- 在Asp.NET Core中如何优雅的管理用户机密数据
在Asp.NET Core中如何优雅的管理用户机密数据 背景 回顾 在软件开发过程中,使用配置文件来管理某些对应用程序运行中需要使用的参数是常见的作法. 在早期VB/VB.NET时代,经常使用.ini ...
最新文章
- C/C++ 静态库和动态库的区别
- Python自然语言处理工具
- electron 打包 php,electron 将现有vue项目改成支持electron桌面端应用
- QT的QReadLocker类的使用
- yum安装时报错,提示/var/run/yum.pid 已被锁定,解决办法
- 用指向指针方法对N个字符串进行排序并输出
- mysql判断是否为null_MySQL如何判断字段是否为null
- [JEEWX问题修复] JeeWX开源版2.3几处代码修改。
- linux目录架构及常用的基本命令
- 实例练习----电影天堂抓取下载链接
- 在 Angular 8 中,我们可以期待些什么
- conda 转载自 生信技能树
- Sock学习1 (网络基本知识、Sock简介)
- 双击计算机图标无法打开,我的电脑图标打不开_我的电脑双击打不开了
- 惊蛰时节,最好看的微信公众号图文排版,全在这里了
- 在祝贺提拔的饭局上当众敬酒,别说“感谢领导”,高手都懂这4点
- iOS 自带地图详解
- 如何TIA博途中更新HSP硬件目录?
- 制作数据集(一):将视频数据剪辑为图片数据
- WebGoat安装及使用说明