Безопасно ли ловить объект исключения - PullRequest
6 голосов
/ 30 мая 2019

Я использую библиотеку Java, которая использует исключения.Упрощенный код ниже:

    try {
      val eventTime = eventTimeString.as[Date]
    } catch {
      case e: Exception =>
        logger.error(s"Can't parse eventTime from $eventTimeString", e)
        // take action for the bad Date string.
    }

В Java я поймал бы только исключение из разбора строки в Date, позволяя остальным остаться необработанными, поскольку они могут быть фатальными.Здесь я понимаю, что поймать Exception означает поймать ЛЮБОЕ несмертельное / несерьезное исключение.Поскольку это не то же самое, что ловит Throwable, это безопасно, но так ли это на самом деле?Основанием для использования этого является то, что неизвестные исключения могут быть выброшены из глубины стека, и если они не являются фатальными, почему бы не перехватить их все.Это всегда было проблемой в Java, где легко найти возможные исключения из прямого вызова, который вы делаете, но не из глубины.Является ли это решение Scala, которое в основном означает «ловить все восстанавливаемые исключения»?

Мой вопрос: считается ли приведенный выше код хорошим стилем Scala, является ли он «безопасным», то есть лучше, чем перехватывать только строку для Dateисключение приведения.

1 Ответ

8 голосов
/ 31 мая 2019

Обращаясь к стилевому аспекту вопроса, Try, как предлагает @LuisMiguelMejiaSuarez, обеспечивает более идиоматический стиль Scala, например, так:

Try(eventTimeString.as[Date]) match {
  case Success(eventTimeDate) => // work with eventTimeDate
  case Failure(e: IllegalArgumentException) => // work with e
  case Failure(e: NullPointerException) => // work with e
  ...
  case Failure(e) => // work with e
}

Синтаксически он выглядит не сильно отличающимся, однако концептуально он довольносдвиг, потому что Success и Failure представляют собой обычные значения , а не исключительную управляющую структуру .Success - это значение, подобное 7 - это значение, тогда как try-catch больше похоже на while или if-else средство управления.

Обертывание любого вызова библиотеки, который может выдать Try, предоставленныйскажем, в библиотеках Java, мы могли бы использовать сахар for-yield для цепочки вызовов, например

for {
  a <- Try(foo)
  b <- Try(bar)
  c <- Try(qux)
} yield {
  // work with a, b and c
}

где

def foo: Int = {
  throw new TimeoutException("foo")
  42
}

def bar: String = {
  throw new IllegalArgumentException("bar")
  "hello"
}

def qux: Boolean = {
  throw new NullPointerException("qux")
  true
}

Мы можем читать эту цепочку последовательно, не прерывая нашупоток мыслей и попытайтесь понять, как какая-то исключительная структура управления вписывается в алгоритм.

Что касается аспекта безопасности вопроса, возможно, мы не должны поймать фатальное исключение, такое как LinkageError, и действительно Try делаетне соответствуют следующим исключениям

VirtualMachineError
ThreadDeath
InterruptedException
LinkageError
ControlThrowable

, как показано на примере построено

object Try {
  def apply[T](r: => T): Try[T] =
    try Success(r) catch {
      case NonFatal(e) => Failure(e)
    }
}

, где NonFatal равно

object NonFatal {
   def apply(t: Throwable): Boolean = t match {
     case _: VirtualMachineError | _: ThreadDeath | _: InterruptedException | _: LinkageError | _: ControlThrowable => false
     case _ => true
   }

  def unapply(t: Throwable): Option[Throwable] = if (apply(t)) Some(t) else None
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...