在scala中处理嵌套可空对象的习惯方法?

时间:2014-06-23 23:50:55

标签: scala

我正在使用scala,并且最近继承了一些需要移植的Java代码,不幸的是在Scala中重写它并不在卡片中。它有一个深层嵌套的对象结构,任何级别都可以为null。我常常只关心嵌套中的深层价值。

理想情况下,我会这样做:

 Option(foo.blah.blarg.doh)

但如果foo.blah.blarg中的任何一个为null,则会产生一个NPE。

现在我已经把它包装在Try:

中了
Try(Option(foo.blah.blarg.doh)).getOrElse(None)

请注意,使用.toOption并不能正常工作,因为如果链的最后一位为空,它可能会导致Some(null)。

我不是特别喜欢这种结构,还有其他任何想法吗?

4 个答案:

答案 0 :(得分:5)

flatMap it:

for {
  a <- Option(foo)
  b <- Option(a.blah)
  c <- Option(b.blarg)
  d <- Option(c.doh)
} yield d

答案 1 :(得分:3)

利用by-name参数构建自己的构造:

def handleNull[T](x: => T): Option[T] = try Option(x) catch {
  case _: NullPointerException => None
}

handleNull(foo.blah.blarg.doh)

答案 2 :(得分:2)

您还可以使用此方法安全地浏览一系列调用,其中每个步骤都可以返回null。它比Option和flatMaps更方便使用。

  /**
    * @param expr expression which is a chain of java calls
    * @tparam A the type of the last expression
    * @return Some(A) if there was no null, None otherwise
    */
  def safeTraverseNullableChain[A](expr: => A): Option[A] = {
    Try(expr).filter(_ != null).toOption
  }

答案 3 :(得分:2)

如果您的项目中有cats库,则可以使用其扩展方法:

  import cats.implicits._

  Either
    .catchOnly[NullPointerException](foo.blah.blarg.doh)
    .collectFirstSome(Option(_))