【Scala】使用Option、Some、None,避免使用null

避免null使用

大多数语言都有一个特殊的关键字或者对象来表示一个对象引用的是“无”,在Java,它是null。在Java 里,null 是一个关键字,不是一个对象,因此对它调用不论什么方法都是非法的。java

但是这对语言设计者来讲是一件使人疑惑的选择。git

为何要在程序猿但愿返回一个对象的时候返回一个关键字呢?github

Scala的Option类型

为了让所有东西都是对象的目标更加一致,也为了遵循函数式编程的习惯。Scala鼓舞你在变量和函数返回值可能不会引用不论什么值的时候使用Option类型。编程

在没有值的时候。使用None,这是Option的一个子类。假设有值可以引用,就使用Some来包括这个值。api

Some也是Option的子类。
None被声明为一个对象,而不是一个类。因为咱们仅仅需要它的一个实例。这样。它多少有点像null关键字。但它倒是一个实实在在的。有方法的对象。数组

应用样例

Option类型的值一般做为Scala集合类型(List,Map等)操做的返回类型。markdown

比方Map的get方法:编程语言

scala> val capitals = Map("France"->"Paris", "Japan"->"Tokyo", "China"->"Beijing")
capitals: scala.collection.immutable.Map[String,String] = Map(France -> Paris, Japan -> Tokyo, China -> Beijing)

scala> capitals get "France"
res0: Option[String] = Some(Paris)

scala> capitals get "North Pole"
res1: Option[String] = None

Option有两个子类别,Some和None。当程序回传Some的时候,表明这个函式成功地给了你一个String,而你可以透过get()函数拿到那个String,假设程序返回的是None。则表明没有字符串可以给你。
在返回None。也就是没有String给你的时候。假设你还硬要调用get()来取得 String 的话,Scala同样是会抛出一个NoSuchElementException异常给你的。ide


咱们也可以选用另一个方法,getOrElse。这种方法在这个Option是Some的实例时返回相应的值,而在是None的实例时返回传入的參数。换句话说。传入getOrElse的參数其实是默认返回值。函数式编程

scala> capitals get "North Pole" get
warning: there was one feature warning; re-run with -feature for details
java.util.NoSuchElementException: None.get
  at scala.None$.get(Option.scala:347)
  at scala.None$.get(Option.scala:345)
  ... 33 elided

scala> capitals get "France" get
warning: there was one feature warning; re-run with -feature for details
res3: String = Paris

scala> (capitals get "North Pole") getOrElse "Oops"
res7: String = Oops

scala> capitals get "France" getOrElse "Oops"
res8: String = Paris

经过模式匹配分离可选值,假设匹配的值是Some的话,将Some里的值抽出赋给x变量:

def showCapital(x: Option[String]) = x match { case Some(s) => s case None => "?

" }

提示

Scala程序使用Option很是频繁,在Java中使用null来表示空值,代码中很是多地方都要加入null关键字检測,否则很是easy出现NullPointException。

所以Java程序需要关心那些变量多是null,而这些变量出现null的可能性很是低,但一但出现,很是难查出为何出现NullPointerException。


Scala的Option类型可以避免这样的状况,所以Scala应用推荐使用Option类型来表明一些可选值。使用Option类型,读者一眼就可以看出这样的类型的值可能为None。

实际上,多亏Scala的静态类型,你并不能错误地尝试在一个可能为null的值上调用方法。

尽管在Java中这是个很是easy犯的错误,它在Scala却通只是编译,这是因为Java中没有检查变量是否为null的编程做为变成Scala中的类型错误(不能将Option[String]当作String来使用)。

因此,Option的使用极强地鼓舞了更加弹性的编程习惯。

具体解释Option[T]

在Scala里Option[T]其实是一个容器,就像数组或是List同样,你可以把他当作是一个可能有零到一个元素的List。
当你的Option里面有东西的时候,这个List的长度是1(也就是 Some)。而当你的Option里没有东西的时候。它的长度是0(也就是 None)。

for循环

假设咱们把Option当成通常的List来用。而且用一个for循环来走訪这个Option的时候,假设Option是None,那这个for循环里的程序代码天然不会运行,因而咱们就达到了「不用检查Option是否为None这件事。

scala> val map1 = Map("key1" -> "value1")
map1: scala.collection.immutable.Map[String,String] = Map(key1 -> value1)

scala> val value1 = map1.get("key1")
value1: Option[String] = Some(value1)

scala> val value2 = map1.get("key2")
value2: Option[String] = None

scala> def printContentLength(x: Option[String]) {
     |   for (c <- x){
     |     println(c.length)
     |   }
     | }
printContentLength: (x: Option[String])Unit

scala> printContentLength(value1)
6

scala> printContentLength(value2)

map操做

在函数式编程中有一个核心的概念之中的一个是转换。因此大部份支持函数式编程语言,都支持一种叫map()的动做。这个动做是可以帮你把某个容器的内容,套上一些动做以后,变成还有一个新的容器。
现在咱们考虑怎样用Option的map方法实现length: xxx的输出形式:

先算出 Option 容器内字符串的长度
而后在长度前面加上 “length: ” 字样
最后把容器走訪一次,印出容器内的东西

scala> value1.map(_.length).map("length: " + _).foreach(println)
length: 6

scala> value1.map("length: " + _.length).foreach(println)
length: 6

透过这样「转换」的方法,咱们同样可以达成想要的效果。而且相同不用去作「是否为 None」的推断。

转载请注明做者Jason Ding及其出处
GitCafe博客主页(http://jasonding1354.gitcafe.io/)
Github博客主页(http://jasonding1354.github.io/)
CSDN博客(http://blog.csdn.net/jasonding1354)
简书主页(http://www.jianshu.com/users/2bd9b48f6ea8/latest_articles)
Google搜索jasonding1354进入个人博客主页

相关文章
相关标签/搜索