Scala 不要在出现错误时停止观察

Scala 不要在出现错误时停止观察,scala,reactive-programming,observable,rx-java,Scala,Reactive Programming,Observable,Rx Java,以下是我目前拥有的Scala代码: val b=可观察的。间隔(1秒)。映射(n=>if(n%2==1) 抛出新异常(其他n*n) b、 订阅(n=>println(n),e=>println(“错误”),()=> println(“完成”)) 这是我的输出: 0 错误 我如何修改我的Observable,使它在每次错误后都能继续运行,我的输出如下: 0 error 2 error 4 ... 您可以使用各种错误处理程序之一。 我认为在您的情况下,OneRorFlatMap可能是正确的选择:

以下是我目前拥有的Scala代码:

val b=可观察的。间隔(1秒)。映射(n=>if(n%2==1) 抛出新异常(其他n*n)

b、 订阅(n=>println(n),e=>println(“错误”),()=> println(“完成”))

这是我的输出:

0
错误

我如何修改我的Observable,使它在每次错误后都能继续运行,我的输出如下:

0
error
2
error
4
...

您可以使用各种错误处理程序之一。 我认为在您的情况下,OneRorFlatMap可能是正确的选择:


不幸的是,OneRorFlatMap(从0.19.0版开始)不是scala api的一部分。

我有同样的问题,对于scala Rx没有OneRorFlatMap感到失望。所以我试了一下 我自己在实现这个功能

我的解决方案如下所示(请参阅解决方案)。关键的方法是:

  def recover[T](target: Observable[T]): Observable[Try[T]] = {
      target.map { Success(_) }.
        onErrorResumeNext(
          (err: Throwable) => Observable.just(Failure(err)) ++ recover(target)
        )
  }
“恢复”方法的详细信息

“recover”的第一个参数是要继续压缩事件的可观测值,即使在 它抛出一个异常。我尝试了所有其他方法,但这是唯一一种有效的方法 我我最初期望Scala Rx的onErrorReturn将任何错误映射到我的恢复所指定的值中 功能,然后继续,但我忽略了“可观察契约”的全部要点,即 在未完成或出错后,可观察对象需要停止发送任何进一步的事件。任何可以观察到的 错误发生后继续喷涌的事件将被贴上“病态”标签(并被上流社会适当避免), 正如这里所讨论的:

成功的onNext调用的有效负载被包装在Success()中,而任何异常都将被处理 通过ONERRORSUMENXT,它将从(1)可观察包装创建连接的可观察流 错误,以及(2)在递归调用中包装目标实例以进行恢复。我最初 担心无限递归。。但一切都很顺利

局限性

我应该提到,在原始海报的问题中——使用observeable.interval 因为recover(target)将是初始的Observable.interval,它将启动 从一开始就发射,所以你永远不会取得进步。对于像interval这样的东西,你会 必须编写自己的基于计时器的时间间隔,以便重新启动。异常值很有希望 提供足够的信息,告诉您需要从中重新启动的值

A SOLUTION




object RecoverFromExceptionsInObservable extends App {

  import rx.lang.scala._
  import scala.language.postfixOps
  import scala.util.{Try, Failure, Success}


  val MILLISECS = 500L
  var tickCount = 0

  /**
   * There is a bug in this code which we will ignore for the simple purpose of
   * this test. The bug is that timers are never stopped and cleaned up.
   */
  def getTickObservable(): Observable[Int] = {
    @volatile var subscribers: Set[Observer[Int]] = Set.empty

    val t = new java.util.Timer()
    val task = new java.util.TimerTask {
      def run() = {
        subscribers.foreach(s => s.onNext(tickCount))
        tickCount += 1
      }
    }
    t.schedule(task, 0L, MILLISECS)

    Observable.create[Int] {
      (obs: Observer[Int]) => {
        subscribers = subscribers + obs
        Subscription {
          subscribers = subscribers - obs
        }
      }
    }
  }

  def recover[T](target: Observable[T]): Observable[Try[T]] = {
      target.map { Success(_) }.
        onErrorResumeNext(
          (err: Throwable) => Observable.just(Failure(err)) ++ recover(target)
        )
  }


  val stream1 = getTickObservable() map { item =>
    if (item % 2 == 0) throw new RuntimeException(s"error on $item") else item
  }

  recover(stream1).subscribe(
    term => {
      println(s" ${Thread.currentThread().getName()}  onNext: $term")
    },
    t => {
      println("in error callback")
      println(s" ${Thread.currentThread().getName()}  onError: $t")
    },
    () => println(s" ${Thread.currentThread().getName()} subscriber complete")
  )
}
以下是上述代码运行的部分输出:

 Timer-0  onNext: Success(1)
 Timer-0  onNext: Failure(java.lang.RuntimeException: error on 2)
 Timer-0  onNext: Success(3)
 Timer-0  onNext: Failure(java.lang.RuntimeException: error on 4)
 Timer-0  onNext: Success(5)
 Timer-0  onNext: Failure(java.lang.RuntimeException: error on 6)

我不希望这个答案永远持续下去,所以我跳过了一些关于解决这个问题的替代方法的细节,如果你感兴趣的话可以阅读。

因为Scala标准库中没有所谓的
Observable
,你应该说你正在使用哪些库。@RandallSchulz我使用的是“RxJava”你能在map函数中捕捉到异常吗?