【问题标题】:Implementing null safe logic in Scala Futures map and flatmap在 Scala Futures map 和 flatmap 中实现 null 安全逻辑
【发布时间】:2013-11-25 13:45:54
【问题描述】:

我的代码由调用 Akka actor 返回的一些 scala.concurrent.Futures 组成

所以我的演员中的示例代码将类似于以下内容:

val ivResult: Future[Any] = ask(ivActor, ivId)

// perform mapping is a function of type (Any) => Unit
val ivMapping: Future[Unit] = ivResult.map(performingMapping)

// erLookup is a function of type (Any) => Future[Any] 
val erResult: Future[Any] = ivResult.flatMap(erLookup)

等等。代码基本上由 future.flatmap().map() 组成,用于执行聚合逻辑

我的问题是我想实现空安全逻辑,这样如果未来的结果为空,那么我们就不会抛出 NullPointerExceptions

显然,我可以在每个函数中嵌入空安全检查,但考虑到 Scala 的强大功能,这些检查似乎有点冗长。

因此,我正在寻找是否有更优雅的方法来做到这一点,也许使用隐式等。

【问题讨论】:

  • 只是不要将null 作为T 的实例返回,而是返回Option[T]grep -r "null" 在您的项目中并修复所有出现的null。如果您有返回 null 的第三方方法,请使用 Option 包装它,如下所示:Option(thirdPartyMethod())
  • 我很想知道您在执行Mapping 和erLookup 函数时做了什么。

标签: scala akka


【解决方案1】:

Future 的结果已经表明它是否成功完成。

通常,在 NPE 上,您的代码会崩溃,未来会失败。

你是说,请不要让我的代码爆炸,可能会产生有害的副作用。

所以你想要一个具有特殊故障状态的守卫。

类似:

scala> object DeadFuture extends Exception with NoStackTrace
defined object DeadFuture

scala> implicit class SafeFuture[A](val f: Future[A]) {
     | def safeMap[B](m: A => B)(implicit x: ExecutionContext) =
     |   f.map { a: A => if (a == null) throw DeadFuture else m(a) }(x)
     | def safeFlatMap[B](m: A => Future[B])(implicit x: ExecutionContext) =
     |   f.flatMap { a: A => if (a == null) (Future failed DeadFuture) else m(a) }(x) 
     | }

然后

scala> case class Datum(i: Int)
defined class Datum

scala> def f(d: Datum): Int = 2 * d.i
f: (d: Datum)Int

scala> def g(d: Datum): Future[Int] = Future(2 * d.i)
g: (d: Datum)scala.concurrent.Future[Int]

scala> Future[Datum](null) safeMap f
res1: scala.concurrent.Future[Int] = scala.concurrent.impl.Promise$DefaultPromise@5fa5debb

scala> .value
res3: Option[scala.util.Try[Int]] = Some(Failure(DeadFuture$))

scala> def g(d: Datum): Future[Int] = Future(2 * d.i)
g: (d: Datum)scala.concurrent.Future[Int]

scala> Future[Datum](null) safeFlatMap g
res4: scala.concurrent.Future[Int] = scala.concurrent.impl.Promise$DefaultPromise@7f188fd

scala> .value
res5: Option[scala.util.Try[Int]] = Some(Failure(DeadFuture$))

可能有更好的方法来诱导转换,所以请保持理解。

for (i <- safely(futureInt)) f(i)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-01
    • 1970-01-01
    • 2021-08-15
    • 2018-05-07
    • 2010-11-06
    相关资源
    最近更新 更多