null の使用を避ける

多くの言語には、オブジェクト参照が「無」であることを示す特別なキーワードまたはオブジェクトがある。Javaではそれはnullである。Javaではnullはキーワードであり、オブジェクトではないため、それに対してメソッドを呼び出すことはすべて非合法である。しかしこれは言語設計者にとって不可解な選択である。プログラマーがオブジェクトを返したいときに、なぜキーワードを返すのだろうか。

Scala の Option型

すべてのものをオブジェクトにするという目標をより一貫させるため、また関数型プログラミングの習慣に従うためにも、Scala では変数や関数の戻り値が何も参照しない可能性がある場合に Option 型を使うことを推奨しています。値がない場合は None を使います。これは Option のサブクラスです。参照する値がある場合は、その値を含めるために Some を使います。Some も Option のサブクラスです。 None はクラスではなくオブジェクトとして宣言されています。なぜなら、そのインスタンスは一つだけでよいからです。このように、None はどことなく null キーワードに似ていますが、実際のメソッドを持つ実にのオブジェクトです。

应用例子

Option型の値は通常、Scalaのコレクション型(List、Mapなど)の操作の戻り値型として使われる。例えば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という2つのサブクラスがある。プログラムがSomeを返すとき、その関数がStringを正常に渡したことを意味し、get()関数でそのStringを取得できる。プログラムがNoneを返す場合は、渡せる文字列がないことを意味する。

None、つまりStringが返されない場合に、それでも無理にget()を呼び出してStringを取得しようとすると、Scalaは同様にNoSuchElementException例外をスローします。 また、別のメソッド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

パターンマッチングによってOptionの値を分離する。マッチした値がSomeの場合、Some内の値を取り出して変数xに代入する:

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

提示

Scala プログラムは Option を非常に頻繁に使用します。Java では null を使って空の値を表すため、コードの多くの場所で null キーワードのチェックを追加する必要があり、そうしないと NullPointException が発生しやすくなります。そのため Java プログラムでは、どの変数が null になる可能性があるかを気にする必要があります。それらの変数が null になる可能性は低いのですが、ひとたび発生すると、なぜ NullPointerException が発生したのかを突き止めるのが難しくなります。 Scala の Option 型はこのような状況を回避できます。そのため Scala アプリケーションでは、オプションの値を表すために Option 型を使うことが推奨されます。Option 型を使えば、読者はこの型の値が None である可能性があることをひと目で見抜けます。

実際には、Scala の静的型付けのおかげで、null になる可能性がある値に対して誤ってメソッドを呼び出すことはできません。Java ではこれは非常に犯しやすいミスですが、Scala ではコンパイルを通りません。これは、Java では変数が null かどうかをチェックしないというプログラミング上の行為が、Scala では型エラーになるからです(Option[String] を String として使うことはできません)。したがって、Option を使うことは、より柔軟なプログラミング習慣を強く促します。

详解 Option[T]

ScalaにおいてOption[T]は実際にはコンテナであり、配列やListと同じように、0個または1個の要素を持つ可能性のある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 操作

関数型プログラミングにおける中核的概念の1つは変換である。したがって、ほとんどの関数型プログラミング対応言語は、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かどうか」の判定を行う必要もない。

原文链接:https://www.jianshu.com/p/95896d06a94d