我有一个方法可以返回< code>Future -成功或失败,甚至可以抛出一个异常。我可以通过在整个方法上放置try catch块并始终返回Future来避免这种情况,但我现在想避免这种情况。我对调用这样的方法没有什么问题:
1)在调用方代码中,如果我使用map
,我希望执行一个方法,并期望一个未来或异常,我试图通过以下方式处理:
object ETLCoordinator {
private def getBusinessListFromModules(modulePaths: Iterable[File]) : Future[String] = {
implicit val ec = ExecutionContext.global
println("Inside getBusinessListFromModules..")
throw new java.lang.RuntimeException("failed to get businesses") //Exception is thrown before future was constructed
Future("ok")
}
def main(args: Array[String]) {
println("Inside Future Test..")
implicit val ec = ExecutionContext.global
val modulePaths = Iterable(new File("mdrqaint/MDR/QAINT/QAINTX"))
val fut1 = getBusinessListFromModules(modulePaths) //This is outside of try and which should be okay
try {
fut1.map { res =>
println("things after Successful fut1")
}.recover{
case t: Throwable => println("Failed future in fut1: "+ t.getMessage)
}
} catch {
case t: Throwable => println("Exception in fut1: "+ t.getMessage)
}
}
}
输出:(上面没有执行恢复或捕获块)
Inside Future Test..
Inside getBusinessListFromModules..
Exception in thread "main" java.lang.RuntimeException: failed to get businesses
但如果我将<code>val fut1=getBusinessListFromModules(modulePath)</code>放在Try块中,则异常在Catch块中被捕获,我得到输出:
Inside Future Test..
Inside getBusinessListFromModules..
Exception in fut1: failed to get businesses
这是为什么?我认为未来的执行会在调用它的一些方法时发生,如map、flatmap、onSuccess、onComplete等。在这种情况下,对<code>map</code>的调用已经在Try块中。
2)定义和调用此类方法的更好方法是什么?在调用者中尝试/捕获块还是在方法本身中尝试/捕获?或任何其他方式。我尝试在Future中包装调用方法,因此我在调用者中获得Future[Future[String]]。我能够避免所有的try-catch。
val fut1 = Future(getBusinessListFromModules(modulePaths))
//try {
fut1.map { res =>
res.map{ str =>
println("things after Successful fut1")
}.recover{
case t: Throwable => println("Failed in future of fut1: "+ t.getMessage)
}
println("things after Successful fut1 wrapper")
}.recover{
case t: Throwable => println("Failed to create future in fut1: "+ t.getMessage)
}
3) 如果中间有另一个方法委托给getBusinessListFromModules
,但它本身不是未来的方法。
object ETLController {
private def getBusinessListFromModules(modulePaths: Iterable[File]) : Future[String] = {
implicit val ec = ExecutionContext.global
println("Inside getBusinessListFromModules..")
//throw new java.lang.RuntimeException("failed to get businesses")
Future("ok")
}
private def callGetBusList(modulePaths: Iterable[File]) : String = {
implicit val ec = ExecutionContext.global
val etlF = getBusinessListFromModules(modulePaths)
etlF onComplete {
case Success(itr) => {
println("Future getBusinessListFromModules success: "+ itr)
throw new java.lang.RuntimeException("RTE from callGetBusList")
}
case Failure(t) => {
println("Future getBusinessListFromModules throws an error")
}
}
"callGetBusList was a success"
}
def main(args: Array[String]) {
println("Inside Future Test..")
implicit val ec = ExecutionContext.global
val modulePaths = Iterable(new File("mdrqaint/MDR/QAINT/QAINTX"))
try {
val fut = Future(callGetBusList(modulePaths))
fut.map { res =>
println("successful future!")
}.recover{
case t: Throwable => println("Failed future: "+ t.getMessage)
}
} catch {
case t: Throwable => println("callGetBusList failed:" + t.getMessage)
}
}
}
输出:(无恢复或捕获块执行!
Inside Future Test..
Inside getBusinessListFromModules..
Future getBusinessListFromModules success: ok
java.lang.RuntimeException: RTE from callGetBusList
at ..
successful future!
我甚至尝试双重包装未来调用:
val fut = Future(Future(callGetBusList(modulePaths)))
fut.map { res =>
res.map { str =>
println("successful inner future! "+ str)
}.recover{
case t: Throwable => println("Failed inner future: "+ t.getMessage)
}
println("successful outer future!")
}.recover{
case t: Throwable => println("Failed outer future: "+ t.getMessage)
}
输出:
Future getBusinessListFromModules success: ok
java.lang.RuntimeException: RTE from callGetBusList
at
successful inner future! callGetBusList was a success
successful outer future!
我得到了“callGetBusList是成功的”,这似乎是onComplete
方法中的RuntimeException
丢失了!我如何在最后一个来电中抓住它?处理此类未来依赖关系的更好实践是什么?
更新:根据@dk14的解释,选择将中间方法转换为返回未来,基本上所有方法都返回某种未来,而不是一个简单的异常。
object ETLController {
private def getBusinessListFromModules(modulePaths: Iterable[File]) : Future[String] = {
implicit val ec = ExecutionContext.global
println("Inside getBusinessListFromModules..")
Future {
Thread.sleep(2000)
throw new java.lang.RuntimeException("failed to get businesses")
"ok"
}
}
private def callGetBusList(modulePaths: Iterable[File]) : Future[String] = {
implicit val ec = ExecutionContext.global
val etlF = getBusinessListFromModules(modulePaths)
etlF map { itr =>
println("Future getBusinessListFromModules success: "+ itr)
throw new java.lang.RuntimeException("RTE from callGetBusList")
} recover {
case t: Throwable => {
println("Future callGetBusList throws an error: " + t.getMessage)
throw t
}
}
}
def main(args: Array[String]) {
println("Inside Future Test..")
implicit val ec = ExecutionContext.global
val modulePaths = Iterable(new File("mdrqaint/MDR/QAINT/QAINTX"))
val fut = callGetBusList(modulePaths)
fut.map { str =>
println("successful future! "+ str)
}.recover{
case t: Throwable => println("Failed future: "+ t.getMessage)
}
println("Active threads: " +Thread.activeCount())
sys.allThreads().foreach(t => t.join())
}
}
1)期货正在急切地开火,它们不是参考透明的。所引用问题的答案还包含有关Future
内部行为的一些见解,因此我想在此处跳过它。
为了以更可预测的方式管理关于执行池/队列/线程的副作用,您可以考虑scalaz/monix/fs2 < code > Task 或iterate/scalaz/cats < code > Eval (更抽象的惰性评估,用于同步)< code>Cont (continuations是对订阅的抽象)作为替代。所有这些都是引用透明的,并且“按需”开始执行。
2) 最好的方法是你不喜欢的方法:不要将异常抛出未来的上下文。
您还可以考虑使用< code>flatMap来避免< code>Future[Future[T]]
3)双包装期货直接a-la 期货(Future(...))
并不能改变什么。您的方法在< code>val etlF = g上执行...(在同一个线程中),不管它返回什么。< code>Future("ok")的内容(lambda)在不同的线程上急切地执行(有“小的”不可预测的延迟),但[执行任务正在提交到池]仍在< code > getBusinessListFromModules 内。
一种解决方法(不推荐)是< code > val etlF = Future(getbusinesslistfromodules(...)).flatMap(identity)返回一个future,包装直接来自< code > getBusinessListFromModules 和间接来自< code > getBusinessListFromModules 的内部< code>Future的任何异常。
最好重构getBusinessListFromModules
本身,但是,对于您的方法可能遇到的不同类型的麻烦(验证,同步与异步等),也会引入不同的异常类型。
有很多方法可以混合异步和同步异常处理,但是实际上很难分析和预测这种混合行为(你可能已经注意到了)。代码变得丑陋。
我希望下面的代码在其中一个方法<code>callfuture1()</code>或<code>callfuture2()</code>抛出异常时返回自定义消息。我的理解是,如果任何一个未来失败,都将是失败的未来。 但是,当 引发异常时。 不执行。相反,我看到调用堆栈停止在 中的代码行,其中发生了异常并返回了标准内部错误。为什么会这样? ====更新==== 我从响应中看到,潜在的问题是异常被抛出
java completableFuture是否有thenComose方法,该方法具有CompletionStage值类型的param来处理异常?像这样的方法: 我想处理结果和异常并使用函数A转换结果,返回完整的Future,就像: 函数A将调用RPC。它是一个异步函数。 复杂uture.handle
我正在寻找一种将任意长度的期货列表转换为期货列表的方法。我使用的是Playframework,所以最终,我真正想要的是一个<code>未来〔结果〕,但为了让事情更简单,让我们说<code>将来〔List[Int]]通常的方法是使用<code>Future.sequence(…) 例如,执行以下操作不起作用: 我希望能够将1和3从那里拉出来,而不是只得到异常。我尝试将来使用<code>。折叠,但这显
我想在我的play scala Web应用程序中进行错误处理。 我的应用程序与数据库对话以获取一些行,它遵循以下流程。 < li >首先调用数据库以获取一些数据 < li >使用第一次调用中的数据从数据库中提取其他数据 < li >使用从最近两次db调用中收到的数据形成响应。 下面是我的伪代码。 以上理解中的每一个方法都返回一个未来,这些方法的签名如下。 在以下情况下,我该如何进行错误/故障处理
我有一些简单的枚举名:失败/成功的结果 我有一个函数,它什么也没有得到,但返回未来的结果, 我不喜欢我的解决方案,它看起来很凌乱,有更简单的吗? 返回 我想在这里做的是,如果返回None,那么func应该返回Future[Fail],否则调用db,这也返回一个case类的未来,并基于响应返回Fail/Success。 但我正在寻找一种超级时尚的斯卡拉方式,让它看起来不错:) 谢谢
我正在阅读Scala Cookbook(http://shop.oreilly.com/product/0636920026914.do) 有一个与未来使用相关的例子,涉及理解。 到目前为止,我对理解的理解是,当与一个集合一起使用时,它会产生另一个相同类型的集合。例如,如果每个< code>futureX的类型为< code>Future[Int],则以下内容也应为< code>Future[In