бросить исключение не работает внутри Scala future.map? - PullRequest
4 голосов
/ 13 мая 2019
def testThrowException(number: Int): Future[Int] = {
 if (number == 0) {
     throw new Exception("number is 0")
 else {
     Future{1}
 }

для вышеуказанной функции, если я вызываю ее с помощью testThrowException (0), я вижу сообщение об ошибке исключения, напечатанное в консоли но если я сделаю что-то вроде

def testThrowException(number: Int): Future[Int] = {
anotherFuture.map {
    if (number == 0) {
        throw new Exception("number is 0")
    } else {
        1
    }
}

Я не могу увидеть исключение, напечатанное в консоли. но если я делаю testThrowException.onFailure, я вижу сообщение об ошибке, я что-то здесь не так сделал? почему исключение не распечатывается

Ответы [ 3 ]

3 голосов
/ 13 мая 2019

В первом примере исключение - это просто голое исключение, возникающее при обнаружении.Это не сильно отличается от чего-то подобного.

def testThrowException(number: Int): Future[Int] = {
  throw new Exception("BOOM!")
  . . . //code to create a Future[Int]

Во втором примере исключение внутри Fututre.Исключение заключено в Future, что приводит к сбою.Вы не увидите ничего, отправленного на консоль, но если вы посмотрите значение результата, вы увидите то, что ищете.

res0: scala.concurrent.Future[Int] = Future(Failure(java.lang.Exception: number is 0))
3 голосов
/ 13 мая 2019

Future работает в отдельном потоке, поэтому выброс внутрь Future просто приводит к сбою этого потока, оставляя основной поток работающим. Например,

object Hello extends App {
  println(s"Starting in main thread called ${Thread.currentThread.getName}...")
  Future(
    throw new RuntimeException(s"I crashed separate thread called ${Thread.currentThread.getName}")
  ).andThen { case Failure(e) => println(e.getMessage) }
  println("I made it!")
}

должен вывести

Starting in main thread called run-main-e...
I made it!
I crashed separate thread called scala-execution-context-global-253

там, где мы видим, произошел сбой отдельного потока с именем scala-execution-context-global-253, в то время как основной поток run-main-e продолжал работать, поэтому I made it! распечатался просто отлично. С другой стороны, следующий пример выбрасывает за пределы Future

object Hello extends App {
  println(s"Starting in main thread called ${Thread.currentThread.getName}...")
  throw new RuntimeException(s"I crashed the main thread ${Thread.currentThread.getName}")
  println("I made it!")
}

который выводит

Starting in main thread called run-main-d...
[error] (run-main-d) java.lang.RuntimeException: I crashed the main thread run-main-d

где мы видим, что основной поток run-main-d потерпел крах до того, как I made it! мог быть напечатан.

2 голосов
/ 13 мая 2019

Первая функция testThrowException не возвращает Future в случае, если она получает 0 в качестве ввода.Поэтому программа продолжает работать, пока не появится исключение.

Однако, как видно из исходного кода, вставленного ниже, Future.map всегда возвращает другое будущее:

  def map[S](f: T => S)(implicit executor: ExecutionContext): Future[S] = { // transform(f, identity)
    val p = Promise[S]()
    onComplete { v => p complete (v map f) }
    p.future
  }

Простое определение будущего не распечатывает его результаты, а также невывести исключения.Для этого вам нужно определить onSuccess, onFailure или onComplete.Однако, если оператор print существует в теле Future, он выполнит:

def addOne(number: Int): Int = {
    if (number == 0) {
        // you can also print the exception instead of just throwing it.
        throw new Exception("number is 0")
    } else {
        println("success")
        1 + number
    }
}
Future { addOne(1) } // scala.concurrent.Future[Int] = Future(Success(2))
// the above also prints "success"
Future { addOne(0) } // scala.concurrent.Future[Int] = Future(Failure(java.lang.Exception: number is 0))
// the above does not print anything unless the exception is printed before thrown in `addOne`

Вы также можете использовать onComplete, чтобы обработать как успех, так и / или неудачу:

// prints "got error" plus the stack trace

 - List item

Future {0}.map(addOne).onComplete {
       case Success(value) => println(s"got $value")
       case Failure(t) => println("got error: " + t.getStackTrace.mkString("\n"))
     }

Обратите внимание, что использовался импорт:

import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global
import scala.util.{Failure, Success}
...