Почему мое будущее Scala не распространяет ошибку? - PullRequest
0 голосов
/ 20 декабря 2018

Этот код работает должным образом:

it("should propagate exceptions") {
  intercept[RuntimeException] {
    val future = Future { Thread.sleep(10); sys.error("whoops"); 22 }
    Await.result(future, Duration.Inf)
  }.getMessage should equal ("whoops")
}

Но это не так:

it("should propagate errors") {
  intercept[StackOverflowError] {
    val future = Future { Thread.sleep(10); throw new StackOverflowError("dang"); 22 }
    Await.result(future, Duration.Inf)
  }.getMessage should equal ("dang")
}

Будущее в этом втором тесте никогда не вернется.Почему подкласс Error (в отличие от подкласса Exception) не ограничивает мое будущее?Как мне обрабатывать Error с?

РЕДАКТИРОВАТЬ: Это, возможно, связано, но не идентично, Почему Scala пытается не перехватить java.lang.StackOverflowError? .Я не использую Try здесь.Основная проблема в том, что Future никогда не возвращается вообще;Я не могу поймать какую-либо ошибку, потому что она просто зависает.

Ответы [ 2 ]

0 голосов
/ 20 декабря 2018

Средство reporter предназначено для катастроф, которые просто подключаются к потоку UncaughtExceptionHandler, но похоже, что он работает "из коробки" только с фабрикой потоков по умолчанию:

scala 2.13.0-M5> import concurrent._,java.util.concurrent.Executors
import concurrent._
import java.util.concurrent.Executors

scala 2.13.0-M5> val ec = ExecutionContext.fromExecutor(null, e => println(s"Handle: $e"))
ec: scala.concurrent.ExecutionContextExecutor = scala.concurrent.impl.ExecutionContextImpl$$anon$3@5e7c141d[Running, parallelism = 4, size = 0, active = 0, running = 0, steals = 0, tasks = 0, submissions = 0]

scala 2.13.0-M5> val f = Future[Int](throw new NullPointerException)(ec)
f: scala.concurrent.Future[Int] = Future(<not completed>)

scala 2.13.0-M5> f
res0: scala.concurrent.Future[Int] = Future(Failure(java.lang.NullPointerException))

scala 2.13.0-M5> val f = Future[Int](throw new StackOverflowError)(ec)
Handle: java.lang.StackOverflowError
f: scala.concurrent.Future[Int] = Future(<not completed>)

, тогда как

scala 2.13.0-M5> val ec = ExecutionContext.fromExecutor(Executors.newSingleThreadExecutor, e => println(s"Handle: $e"))
ec: scala.concurrent.ExecutionContextExecutor = scala.concurrent.impl.ExecutionContextImpl@317a118b

scala 2.13.0-M5> val f = Future[Int](throw new StackOverflowError)(ec)
f: scala.concurrent.Future[Int] = Future(<not completed>)
Exception in thread "pool-1-thread-1" java.lang.StackOverflowError
    at $line14.$read$$iw$$iw$$iw$$iw$.$anonfun$f$1(<console>:1)
    at scala.concurrent.Future$.$anonfun$apply$1(Future.scala:659)
    at scala.util.Success.$anonfun$map$1(Try.scala:261)
    at scala.util.Success.map(Try.scala:209)
    at scala.concurrent.impl.Promise$Transformation.doMap(Promise.scala:420)
    at scala.concurrent.impl.Promise$Transformation.run(Promise.scala:402)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    at java.lang.Thread.run(Thread.java:748)

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

0 голосов
/ 20 декабря 2018

Как указано в комментариях, это дубликат Почему Scala пытается не перехватить java.lang.StackOverflowError?

Согласно документации Scala.

Примечание: комбинаторы перехватывают только нефатальные исключения (см.> Scala.util.control.NonFatal).Серьезные системные ошибки, с другой стороны, будут> выброшены.

No Throwable -> Ошибки отлавливаются Try

Также, чтобы ответить на ваш вопрос о том, как обычно выполняется обработка ошибок,В Scala вы можете использовать try / catch для кода, который может вызывать исключения (очень похожие на Java):

try { 
// ... Your dangerous code in here
} catch {
 case ioe: IOException => ... //
 case e: Exception => ...
} 

И у вас всегда должны быть сначала более конкретные исключения.

Код, который выпри условии будет выглядеть примерно так: https://scastie.scala -lang.org / 2DJXJ6ESS9ySJZSwSodmZg

Кроме того, я опробовал ваш код, и он определенно вызывает StackOverFlowerror.Но он не может поймать его правильно, как объясняет вышеупомянутая ссылка.

...