用 option 代替 null

2018-02-24 15:59 更新

null 的問題

Map<String, String> map = ???
String valFor2014 = map.get(“1024”); // null

if (valFor1024 == null)
    abadon();
else doSomething();
  • null到底代表key找不到還是說1024對應(yīng)的值就是null?
  • 某年某月某日,我把為null則abandon這段代碼寫了100遍.

option介紹

  • option可以看作是一個容器,容器的size是1或0
  • Size為1的時候就是一個Some[A](x: A),size為0的時候就是一個None

看看scala的map

def get(key: A): Option[B]

def getOrElse[B1 >: B](key: A, default: => B1): B1 = get(key) match {
  case Some(v) => v
  case None => default
}
  • 可以區(qū)分Map中到底又沒有這個key.
  • 我見過許多java項目自己實現(xiàn)了getOrElse這個方法并放在一個叫做MapUtils的類里.
  • 為什么java經(jīng)過這么多代演進,Map仍然沒有默認(rèn)包含這個方法,一直想不通.
    (寫完這段突然發(fā)現(xiàn)java8開始包含getOrDefault了)

好像沒有太大區(qū)別?

確實能夠區(qū)分Map是無值還是值為null了.
但是if(為null) 則 abandon 要寫一百遍.
case Some(v) => v
case None => default
似乎也得寫一百遍.

不,不是這樣的
不要忘了option是個容器
http://www.scala-lang.org/api/2.11.7/index.html#scala.Option

試試容器里的各種方法

val a: Option[String] = Some("1024")
val b: Option[String] = None
a.map(_.toInt)
//res0: Option[Int] = Some(1024)
b.map(_.toInt)
//res1: Option[Int] = None,不會甩exception
a.filter(_ == "2048")
//res2: Option[String] = None
b.filter(_ == "2048")
//res3: Option[String] = None
a.getOrElse("2048")
//res4: String = 1024
b.getOrElse("2048")
//res5: String = 2048
a.map(_.toInt)
  .map(_ + 1)
  .map(_ / 5)
  .map(_ / 2 == 0) //res6: Option[Boolean] = Some(false)
//如果是null,恐怕要一連check abandon四遍了

option配合其他容器使用

val a: Seq[String] =
  Seq("1", "2", "3", null, "4")
val b: Seq[Option[String]] =
  Seq(Some("1"), Some("2"), Some("3"), None, Some("4"))

a.filter(_ != null).map(_.toInt)
//res0: Seq[Int] = List(1, 2, 3, 4)
//如果你忘了檢查,編譯器是看不出來的,只能在跑崩的時候拋異常
b.flatMap(_.map(_.toInt))
//res1: Seq[Int] = List(1, 2, 3, 4)
  • option幫助你把錯誤扼殺在編譯階段
  • flatMap則可以在過濾空值的同時將option恢復(fù)為原始數(shù)據(jù).

scala原生容器類都對option有良好支持

Seq(1,2,3).headOption
//res0: Option[Int] = Some(1)

Seq(1,2,3).find(_ == 5)
//res1: Option[Int] = None

Seq(1,2,3).lastOption
//res2: Option[Int] = Some(3)

Vector(1,2,3).reduceLeft(_ + _)
//res3: Int = 6

Vector(1,2,3).reduceLeftOption(_ + _)
//res4: Option[Int] = Some(6)
//在vector為空的時候也能用

Seq("a", "b", "c", null, "d").map(Option(_))
//res0: Seq[Option[String]] =
// List(Some(a), Some(b), Some(c), None, Some(d))
//原始數(shù)據(jù)轉(zhuǎn)換成option也很方便
以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號