utilizar tag resueltos responder questions question las hacer excepciones entonacion ejercicios ejemplos correctamente con como aprende scala exception logging

scala - tag - Probar con el registro de excepciones



tag questions con i (4)

Al iniciar Scala 2.13 , se puede usar la operación de encadenamiento para aplicar un efecto secundario (en este caso, algunos registros) en cualquier valor mientras se devuelve el valor original:

import util.chaining._ val x = Try("aa".toInt).tap(_.failed.foreach(println)) // java.lang.NumberFormatException: For input string: "aa" // x: Try[Int] = Failure(java.lang.NumberFormatException: For input string: "aa")

O una versión de coincidencia de patrón equivalente:

val x = Try("aa".toInt).tap { case Failure(e) => println(e) case _ => } // java.lang.NumberFormatException: For input string: "aa" // x: Try[Int] = Failure(java.lang.NumberFormatException: For input string: "aa")

La operación de encadenamiento de tap aplica un efecto secundario (en este caso, println o algún registro) sobre un valor (en este caso, una Try ) mientras devuelve el valor original sin modificar al que se aplica la tap (la Try ):

def pulse [U] (f: (A) => U): A

El Try de Scala es muy útil.

Me gustaría usar ese patrón, pero registrar todas las excepciones.

¿Cómo puedo hacer esto?


Define el siguiente ayudante:

import scala.util.{Try, Failure} def LogTry[A](computation: => A): Try[A] = { Try(computation) recoverWith { case e: Throwable => log(e) Failure(e) } }

Luego puede usarlo como lo haría con Try , pero cualquier excepción se registrará a través del log(e) .


Puedes modificarlo aún más usando la clase implícita

def someMethod[A](f: => A): Try[A] = Try(f) implicit class LogTry[A](res: Try[A]) { def log() = res match { case Success(s) => println("Success :) " + s); res case Failure(f) => println("Failure :( " + f); res } }

Ahora puede llamar a someMethod y en su log llamadas de resultados como este:

scala> someMethod(1/0).log Failure :( java.lang.ArithmeticException: / by zero

y

scala> someMethod(1).log Success :) 1

Por supuesto, el método println dentro de la clase implícita puede sustituirse con cualquier registro que desee.


Usaste el término "excepciones" que es ambiguo. (java.lang.)Throwable es la raíz de cualquier cosa que pueda colocarse detrás del término de throw . java.lang.Exception es uno de los dos descendientes de (java.lang.)Throwable (el otro es java.lang.Error ). Además de hacer esto ambiguo está java.lang.RuntimeException , un descendiente de Exception , que es probablemente donde más desea pasar su tiempo de registro (a menos que esté haciendo implementaciones de controlador de hardware o marco de aplicaciones de nivel inferior).

Suponiendo que desea registrar literalmente TODAS las instancias de Throwable, entonces necesitará algo como esto (NO RECOMENDADO):

def logAtThrowable(f: => A): Try[A] = try Try(f) match { case failure @ Failure(throwable) => log(s"Failure: {throwable.getMessage}") failure case success @ _ => //uncomment out the next line if you want to also log Success-es //log(s"Success: {throwable.getMessage}") success } catch throwable: Throwable => { //!NonFatal pathway log(s"Failure: {throwable.getMessage}") throw throwable }

El try/catch externo es necesario para capturar todas las instancias de scala.util.control.NonFatal que se eliminan por medio de scala.util.control.NonFatal dentro del bloque try / catch Try .

Dicho esto ... hay una regla de Java / JVM: nunca debe definir una cláusula catch en la resolución de Throwable (de nuevo, a menos que esté haciendo implementaciones de controlador de hardware o marco de aplicaciones de nivel inferior).

Siguiendo la intención de esta regla, necesitaría restringir el Throwable para que solo emita el registro en el nivel de grano más fino, diga algo más refinado, como java.lang.RuntimeException . Si es así, el código se vería así (recomendado):

def logAtRuntimeException(f: => A): Try[A] = Try(f) match { case failure @ Failure(throwable) => throwable match { case runtimeException: RuntimeException => log(s"Failure: {runtimeException.getMessage}") } failure case success @ _ => success }

En los dos fragmentos de código anteriores, notará que usé match en lugar de .recoverWith . Esto es para facilitar fácilmente la adición de un throw re que funciona. Resulta que todos los métodos en Try también están envueltos con bloques try / catch . Esto significa que si desea registrar el Throwable y luego volver a throw , si está utilizando uno de los métodos de Try , como recoverWith , el relanzamiento se recupera inmediatamente y se coloca en una Failure , minando así completamente el valor del relanzamiento intencional. Mediante el uso de la match , se garantiza que el relanzará con éxito ya que permanece fuera de cualquiera de los métodos de Try .

Si desea ver más agujeros de conejos en esta área en particular, creé una fromjavatoscala.blogspot.com/2016/09/… .