Подтвердить что ты не робот

Попробуйте с регистрацией исключений

Scala Try очень полезен.

Я хотел бы использовать этот шаблон, но регистрировать все исключения.

Как я могу это сделать?

4b9b3361

Ответ 1

Определите следующий помощник:

import scala.util.{Try, Failure}

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

Затем вы можете использовать его так же, как и Try, но любое исключение будет зарегистрировано через log(e).

Ответ 2

Вы можете настроить его еще больше, используя неявный класс

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
  }
}

Теперь вы можете вызвать someMethod и его результат log следующим образом:

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

и

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

Конечно, метод println внутри неявного класса может быть заменен любым ведением журнала.

Ответ 3

Вы использовали термин "исключения", который неоднозначен. (java.lang.)Throwable является корнем всего, что может быть помещено за термином throw. java.lang.Exception является одним из двух потомков Throwable (другое java.lang.Error). Дальнейшее создание этого двусмысленного - java.lang.RuntimeException, потомок Exception, который, вероятно, там, где вы в основном хотите потратить время регистрации (если только вы занимаются инфраструктурой приложений нижнего уровня или реализацией аппаратных драйверов).

Предполагая, что вы хотите записать буквально ВСЕ экземпляры Throwable, вам понадобится что-то вроде этого (НЕ РЕКОМЕНДУЕТСЯ):

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
  }

Внешний try/catch требуется для захвата всех экземпляров Throwable, отфильтрованных scala.util.control.NonFatal в Try Try/catch.

Это говорит... существует правило Java/JVM: вы должны никогда не определять предложение catch в разрешении Throwable (опять же, если вы не используете инфраструктуру приложений нижнего уровня или версии аппаратного драйвера).

Следуя намерению этого правила, вам нужно будет сузить Throwable до того, как вы только вышли из системы на более тонком уровне, скажите что-то более совершенное, например java.lang.RuntimeException. Если это так, код будет выглядеть так (рекомендуется):

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
  }

В обоих фрагментах кода выше вы заметите, что я использовал match, а не .recoverWith. Это облегчает добавление re throw, который работает. Оказывается, что все методы на Try сами также обернуты блоками Try/catch. Это означает, что если вы хотите зарегистрировать Throwable, а затем re throw, то, если вы используете один из методов Try, например recoverWith, re throw немедленно возвращается и помещается в Failure тем самым полностью подрывая значение преднамеренного re throw. Используя match, re throw будет успешным, поскольку он остается вне любого из методов Try.

Если вы хотите увидеть больше кроличьих дыр вокруг этой конкретной области, я создал сообщение в блоге моего собственного исследования.

Ответ 4

Начиная с Scala 2.13, U):A rel="nofollow noreferrer"> tap операции U):A rel="nofollow noreferrer"> tap можно использовать для применения побочного эффекта (в данном случае некоторого ведения журнала) к любому значению при возврате исходного значения:

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")

Или эквивалентная версия сопоставления с образцом:

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")

Операция цепочки U):A rel="nofollow noreferrer"> tap применяет побочный эффект (в данном случае println или некоторую запись в журнал) к значению (в данном случае - " Try), возвращая исходное неизмененное значение, к которому применяется tap (Try):

def нажмите [U] (f: (A) => U): A