使用 Option 而不是 Null

在 Java(和其他語言)中,使用 null 是表示沒有附加到引用變數的值的常用方法。在 Scala 中,使用 Option 比使用 null 更受歡迎。Option 包含可能null 的值。

None 是包含空引用的 Option 的子類。Some 是包含非空引用的 Option 的子類。

包裝參考很容易:

val nothing = Option(null) // None
val something = Option("Aren't options cool?") // Some("Aren't options cool?")

這是呼叫可能返回 null 引用的 Java 庫時的典型程式碼:

val resource = Option(JavaLib.getResource())
// if null, then resource = None
// else resource = Some(resource)

如果 getResource() 返回 null 值,則 resource 將成為 None 物件。否則它將是一個 Some(resource) 物件。處理 Option 的首選方法是使用 Option 型別中的高階函式。例如,如果你想檢查你的值是不是 None(類似於檢查 value == null),你會使用 isDefined 函式:

val resource: Option[Resource] = Option(JavaLib.getResource())
if (resource.isDefined) {  // resource is `Some(_)` type
  val r: Resource = resource.get
  r.connect()
}

同樣,要檢查 null 參考,你可以這樣做:

val resource: Option[Resource] = Option(JavaLib.getResource())
if (resource.isEmpty) { // resource is `None` type.
  System.out.println("Resource is empty! Cannot connect.")
}

你最好將 Option 視為 monad 並使用 foreach 處理 Option 的包裝值(不使用’特殊’Option.get 方法)的條件執行:

val resource: Option[Resource] = Option(JavaLib.getResource())
resource foreach (r => r.connect())
// if r is defined, then r.connect() is run
// if r is empty, then it does nothing

如果需要 Resource 例項(與 Option[Resource] 例項相比),你仍然可以使用 Option 來防止空值。這裡 getOrElse 方法提供了一個預設值:

lazy val defaultResource = new Resource()
val resource: Resource = Option(JavaLib.getResource()).getOrElse(defaultResource)

Java 程式碼不會輕易處理 Scala 的 Option,因此在將值傳遞給 Java 程式碼時,開啟 Option,傳遞 null 或合理的預設值是一種很好的形式:

val resource: Option[Resource] = ???
JavaLib.sendResource(resource.orNull)
JavaLib.sendResource(resource.getOrElse(defaultResource)) //