即使在Scala中捕获异常后仍执行代码块

即使在Scala中捕获异常后仍执行代码块,scala,exception-handling,Scala,Exception Handling,在我当前的方法中,我尝试进行一系列调用,如果其中任何一个调用失败,我希望能够继续运行其余的调用,同时捕获抛出的异常。在Scala,我很难弄明白这一点 所以在这个例子中,我想启动这些调用中的每一个——RunA、RunB和RunC,但是如果RunB抛出一个异常,我想打印它,然后继续启动RunC var result = Try { new RunA() new RunB() new RunC() } catch { case e: Throwable =>

在我当前的方法中,我尝试进行一系列调用,如果其中任何一个调用失败,我希望能够继续运行其余的调用,同时捕获抛出的异常。在Scala,我很难弄明白这一点

所以在这个例子中,我想启动这些调用中的每一个——RunA、RunB和RunC,但是如果RunB抛出一个异常,我想打印它,然后继续启动RunC

var result = Try {
    new RunA()
    new RunB()
    new RunC()
}   catch { 
    case e: Throwable => e.printStackTrace()
    false
 }
除了将它们单独包装在一个Try/Catch中之外,我确信还有更好的方法来做到这一点,这就是为什么我希望有人能帮上忙的原因

我查看了“忽略”异常,但它似乎完全忽略了我至少要记录的异常


谢谢

您将scala.util.Try与Try{}catch{}混合使用,这是不同的概念。Try将函数包装到Successresult或Failureerror类中,Try-catch类似于Java Try-catch。我建议你这样做:

  class RunA
  class RunB
  class RunC
  class Result(a: RunA, b: RunB, c: RunC)

  implicit class LogFailure[T](t: Try[T]) {
    def logFailure: Try[T] = t match {
      case scala.util.Failure(err) => err.printStackTrace(); t
      case _ => t
    }
  }

  val tryA= Try(new RunA())
  val tryB= Try(new RunB())
  val tryC = Try(new RunC())

  val result: Try[Result] = for {
    a <- tryA.logFailure
    b <- tryB.logFailure
    c <- tryC.logFailure
  } yield {
    // do smth with a, b, c
    new Result(a, b, c)
  }
import scala.reflect.ClassTag
import scala.util.{Try, Success, Failure}

def tryAndLog[T: ClassTag] = Try {
    implicitly[ClassTag[T]].runtimeClass.newInstance.asInstanceOf[T] // new instance
} match {
    case Success(_) => true
    case Failure(ex) => ex.printStackTrace ; false
}    

def tryRunAll = {
    val A = tryAndLog[RunA]
    val B = tryAndLog[RunB]
    val C = tryAndLog[RunC]
    A && B && C  // returns true if all invocations succeeded, false otherwise
}

如果A、B、C成功,您将获得成功结果如果其中一个失败,您将获得第一个异常的失败,但是所有这些都将记录为打印堆栈跟踪

您将scala.util.Try与Try{}catch{}混合使用,这是不同的概念。Try将函数包装到Successresult或Failureerror类中,Try-catch类似于Java Try-catch。我建议你这样做:

  class RunA
  class RunB
  class RunC
  class Result(a: RunA, b: RunB, c: RunC)

  implicit class LogFailure[T](t: Try[T]) {
    def logFailure: Try[T] = t match {
      case scala.util.Failure(err) => err.printStackTrace(); t
      case _ => t
    }
  }

  val tryA= Try(new RunA())
  val tryB= Try(new RunB())
  val tryC = Try(new RunC())

  val result: Try[Result] = for {
    a <- tryA.logFailure
    b <- tryB.logFailure
    c <- tryC.logFailure
  } yield {
    // do smth with a, b, c
    new Result(a, b, c)
  }
import scala.reflect.ClassTag
import scala.util.{Try, Success, Failure}

def tryAndLog[T: ClassTag] = Try {
    implicitly[ClassTag[T]].runtimeClass.newInstance.asInstanceOf[T] // new instance
} match {
    case Success(_) => true
    case Failure(ex) => ex.printStackTrace ; false
}    

def tryRunAll = {
    val A = tryAndLog[RunA]
    val B = tryAndLog[RunB]
    val C = tryAndLog[RunC]
    A && B && C  // returns true if all invocations succeeded, false otherwise
}
如果A、B、C将成功,您将获得成功结果如果其中一个失败,您将获得第一个异常的失败,但是所有这些都将被记录为打印堆栈跟踪

首先,不要将try{…}catch{…}与scala.util混合使用。try{…}

你可以

import scala.util._
val runA = Try{ new RunA }
val runB = Try{ new RunB }
val runC = Try{ new RunC }
然后处理你认为合适的异常。例如,如果要打印并继续,可以在此处处理try语句:

def getOrPrint[A](f: => A): Option[A] = Try{ f } match {
  case Success(x) => Some(x)
  case Failure(e) => e.printStackTrace; None
}

getOrPrint{ new RunA }
...
首先,不要将try{…}catch{…}与scala.util.try{…}混在一起

你可以

import scala.util._
val runA = Try{ new RunA }
val runB = Try{ new RunB }
val runC = Try{ new RunC }
然后处理你认为合适的异常。例如,如果要打印并继续,可以在此处处理try语句:

def getOrPrint[A](f: => A): Option[A] = Try{ f } match {
  case Success(x) => Some(x)
  case Failure(e) => e.printStackTrace; None
}

getOrPrint{ new RunA }
...

使用scalaz可以有更优雅的方式来完成这类事情,例如,在这里阅读一篇文章,获得一些灵感:,但只有使用Scala,您可以执行以下操作:

  class RunA
  class RunB
  class RunC
  class Result(a: RunA, b: RunB, c: RunC)

  implicit class LogFailure[T](t: Try[T]) {
    def logFailure: Try[T] = t match {
      case scala.util.Failure(err) => err.printStackTrace(); t
      case _ => t
    }
  }

  val tryA= Try(new RunA())
  val tryB= Try(new RunB())
  val tryC = Try(new RunC())

  val result: Try[Result] = for {
    a <- tryA.logFailure
    b <- tryB.logFailure
    c <- tryC.logFailure
  } yield {
    // do smth with a, b, c
    new Result(a, b, c)
  }
import scala.reflect.ClassTag
import scala.util.{Try, Success, Failure}

def tryAndLog[T: ClassTag] = Try {
    implicitly[ClassTag[T]].runtimeClass.newInstance.asInstanceOf[T] // new instance
} match {
    case Success(_) => true
    case Failure(ex) => ex.printStackTrace ; false
}    

def tryRunAll = {
    val A = tryAndLog[RunA]
    val B = tryAndLog[RunB]
    val C = tryAndLog[RunC]
    A && B && C  // returns true if all invocations succeeded, false otherwise
}

使用scalaz可以有更优雅的方式来完成这类事情,例如,在这里阅读一篇文章,获得一些灵感:,但只有使用Scala,您可以执行以下操作:

  class RunA
  class RunB
  class RunC
  class Result(a: RunA, b: RunB, c: RunC)

  implicit class LogFailure[T](t: Try[T]) {
    def logFailure: Try[T] = t match {
      case scala.util.Failure(err) => err.printStackTrace(); t
      case _ => t
    }
  }

  val tryA= Try(new RunA())
  val tryB= Try(new RunB())
  val tryC = Try(new RunC())

  val result: Try[Result] = for {
    a <- tryA.logFailure
    b <- tryB.logFailure
    c <- tryC.logFailure
  } yield {
    // do smth with a, b, c
    new Result(a, b, c)
  }
import scala.reflect.ClassTag
import scala.util.{Try, Success, Failure}

def tryAndLog[T: ClassTag] = Try {
    implicitly[ClassTag[T]].runtimeClass.newInstance.asInstanceOf[T] // new instance
} match {
    case Success(_) => true
    case Failure(ex) => ex.printStackTrace ; false
}    

def tryRunAll = {
    val A = tryAndLog[RunA]
    val B = tryAndLog[RunB]
    val C = tryAndLog[RunC]
    A && B && C  // returns true if all invocations succeeded, false otherwise
}

太好了,这正是我想要的。现在唯一的问题是我必须修改getOrPrint以返回一个布尔值,然后我必须按照其他人的建议&&来聚合我的结果。不幸的是,这在我的解决方案中导致了一个纠结,当我测试失败时,它返回一个false,我必须将None更改为false,然后它停止执行。有很多方法可以解决这个问题,所以我会尝试单独解决。很好,这正是我想要的。现在唯一的问题是我必须修改getOrPrint以返回一个布尔值,然后我必须按照其他人的建议&&来聚合我的结果。不幸的是,这在我的解决方案中导致了一个纠结,当我测试失败时,它返回一个false,我必须将None更改为false,然后它停止执行。有很多方法可以解决这个问题,所以我将尝试单独解决。