我正在寻找一种将任意长度的期货列表转换为期货列表的方法。我使用的是Playframework,所以最终,我真正想要的是一个<code>未来〔结果〕,但为了让事情更简单,让我们说<code>将来〔List[Int]]通常的方法是使用<code>Future.sequence(…)
例如,执行以下操作不起作用:
import scala.concurrent._
import scala.concurrent.ExecutionContext.Implicits.global
import scala.util.Success
import scala.util.Failure
val listOfFutures = Future.successful(1) :: Future.failed(new Exception("Failure")) ::
Future.successful(3) :: Nil
val futureOfList = Future.sequence(listOfFutures)
futureOfList onComplete {
case Success(x) => println("Success!!! " + x)
case Failure(ex) => println("Failed !!! " + ex)
}
scala> Failed !!! java.lang.Exception: Failure
我希望能够将1和3从那里拉出来,而不是只得到异常。我尝试将来使用<code>。折叠,但这显然只是调用未来。序列在幕后。
提前感谢您的帮助!
我尝试了凯文的答案,我在我的Scala版本(2.11.5)上遇到了一个小故障......我纠正了这一点,并写了一些额外的测试,如果有人感兴趣的话......这是我的版本
implicit class FutureCompanionOps(val f: Future.type) extends AnyVal {
/** Given a list of futures `fs`, returns the future holding the list of Try's of the futures from `fs`.
* The returned future is completed only once all of the futures in `fs` have been completed.
*/
def allAsTrys[T](fItems: /* future items */ List[Future[T]]): Future[List[Try[T]]] = {
val listOfFutureTrys: List[Future[Try[T]]] = fItems.map(futureToFutureTry)
Future.sequence(listOfFutureTrys)
}
def futureToFutureTry[T](f: Future[T]): Future[Try[T]] = {
f.map(Success(_)) .recover({case x => Failure(x)})
}
def allFailedAsTrys[T](fItems: /* future items */ List[Future[T]]): Future[List[Try[T]]] = {
allAsTrys(fItems).map(_.filter(_.isFailure))
}
def allSucceededAsTrys[T](fItems: /* future items */ List[Future[T]]): Future[List[Try[T]]] = {
allAsTrys(fItems).map(_.filter(_.isSuccess))
}
}
// Tests...
// allAsTrys tests
//
test("futureToFutureTry returns Success if no exception") {
val future = Future.futureToFutureTry(Future{"mouse"})
Thread.sleep(0, 100)
val futureValue = future.value
assert(futureValue == Some(Success(Success("mouse"))))
}
test("futureToFutureTry returns Failure if exception thrown") {
val future = Future.futureToFutureTry(Future{throw new IllegalStateException("bad news")})
Thread.sleep(5) // need to sleep a LOT longer to get Exception from failure case... interesting.....
val futureValue = future.value
assertResult(true) {
futureValue match {
case Some(Success(Failure(error: IllegalStateException))) => true
}
}
}
test("Future.allAsTrys returns Nil given Nil list as input") {
val future = Future.allAsTrys(Nil)
assert ( Await.result(future, 100 nanosecond).isEmpty )
}
test("Future.allAsTrys returns successful item even if preceded by failing item") {
val future1 = Future{throw new IllegalStateException("bad news")}
var future2 = Future{"dog"}
val futureListOfTrys = Future.allAsTrys(List(future1,future2))
val listOfTrys = Await.result(futureListOfTrys, 10 milli)
System.out.println("successItem:" + listOfTrys);
assert(listOfTrys(0).failed.get.getMessage.contains("bad news"))
assert(listOfTrys(1) == Success("dog"))
}
test("Future.allAsTrys returns successful item even if followed by failing item") {
var future1 = Future{"dog"}
val future2 = Future{throw new IllegalStateException("bad news")}
val futureListOfTrys = Future.allAsTrys(List(future1,future2))
val listOfTrys = Await.result(futureListOfTrys, 10 milli)
System.out.println("successItem:" + listOfTrys);
assert(listOfTrys(1).failed.get.getMessage.contains("bad news"))
assert(listOfTrys(0) == Success("dog"))
}
test("Future.allFailedAsTrys returns the failed item and only that item") {
var future1 = Future{"dog"}
val future2 = Future{throw new IllegalStateException("bad news")}
val futureListOfTrys = Future.allFailedAsTrys(List(future1,future2))
val listOfTrys = Await.result(futureListOfTrys, 10 milli)
assert(listOfTrys(0).failed.get.getMessage.contains("bad news"))
assert(listOfTrys.size == 1)
}
test("Future.allSucceededAsTrys returns the succeeded item and only that item") {
var future1 = Future{"dog"}
val future2 = Future{throw new IllegalStateException("bad news")}
val futureListOfTrys = Future.allSucceededAsTrys(List(future1,future2))
val listOfTrys = Await.result(futureListOfTrys, 10 milli)
assert(listOfTrys(0) == Success("dog"))
assert(listOfTrys.size == 1)
}
Scala 2.12在<code>的未来有了改进。转换,使其自身处于代码较少的anwser中。
val futures = Seq(Future{1},Future{throw new Exception})
// instead of `map` and `recover`, use `transform`
val seq = Future.sequence(futures.map(_.transform(Success(_))))
val successes = seq.map(_.collect{case Success(x)=>x})
successes
//res1: Future[Seq[Int]] = Future(Success(List(1)))
val failures = seq.map(_.collect{case Failure(x)=>x})
failures
//res2: Future[Seq[Throwable]] = Future(Success(List(java.lang.Exception)))
诀窍是首先确保没有一个期货失败。.recover
是你在这里的朋友,你可以将它与 map
结合使用,将所有 Future[T]
结果转换为 Future[Try[T]]]
实例,所有这些实例都一定是成功的期货。
注意:您也可以在此处使用Option
或任一
,但如果您特别想捕获异常,尝试
是最干净的方法
def futureToFutureTry[T](f: Future[T]): Future[Try[T]] =
f.map(Success(_)).recover { case x => Failure(x)}
val listOfFutures = ...
val listOfFutureTrys = listOfFutures.map(futureToFutureTry(_))
然后在将来使用。顺序
与前面一样,为您提供一个未来的列表[Try[T]]]
val futureListOfTrys = Future.sequence(listOfFutureTrys)
然后过滤:
val futureListOfSuccesses = futureListOfTrys.map(_.filter(_.isSuccess))
如果需要,您甚至可以提取特定的故障:
val futureListOfFailures = futureListOfTrys.map(_.filter(_.isFailure))
我希望像下面这样的代码可以等待这两种未来,但是没有。 我以为< code>seq.onComplete会在完成自身之前等待它们全部完成,但事实并非如此;它会导致: 在scala.concurrent.Future的源代码中有点难以遵循,我想知道如何实现等待(动态大小的)序列的所有原始未来的并行,或者这里可能有什么问题。 编辑:相关问题:https://worldbuilding.stackexch
Scala中有没有不会失败的< code >未来这个概念? 我正在将可能失败,因此我同时处理和--到,并带有从失败或成功状态派生的可选错误消息。目前为止,一切都好。 现在的情况是,我想正式地(即在类型系统的帮助下)记住,这个未来将始终保持,并且我将来不需要处理失败案例。 有什么聪明的方法可以做到这一点吗?
我正在开发一个用Scala编写的PlayFramework应用程序。 问题在于,在rest控制器中,我需要一个元素列表(书籍),每个元素都需要一个子元素列表(章节)。 图书仓库: 章节存储库: 我想做一些像 我想要一个图书及其章节的元组,这样我可以稍后将它映射到一个json。我做错了什么,因为我得到错误: 或者什么是更好的方法,如何迭代集合的未来,并为每个元素加载另一个集合的未来?
在Scala中,未来可能会失败,这可以异步发现: 你将如何“翻译”成Clojure?我的阅读让我相信Clojure未来/promise模型没有Scala的强大,你不能就这样抓住失败。那么该怎么办呢? Scala的未来永远不需要被问到它的价值——当它好并准备好时,它会告诉你发生了什么(包括它是否失败——这是这个问题的关键)。这就是我所说的“异步”的意思。Scala的未来可以处于三种可能的状态之一——
我有一个对象,我想将其转换为
AFAIK将/提交到是我想并行执行资源密集型代码的方法。因此,我的方法结构: 我在上面的代码中标记了两个可能发生故障的点。对于这两种情况,可用于错误处理的选项非常不同。 在提交任务之前,可能会出现一些问题,例如参数无效,一些可能失败的快速预处理代码。 我在这里看到了几种表示失败的方式: 如果提供给的无效立即返回null。在这种情况下,我必须检查每次调用时是否返回null。 抛出检查过的异常而不是上