【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進入個人博客主頁

相關文章
相關標籤/搜索