Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // Let's test NonFatal in sync and async code!
- // 1. InterruptedException in try/catch-all pattern:
- package ru.mitrakov.self.sandbox
- import java.time.LocalDateTime
- import scala.concurrent.ExecutionContext.Implicits.global
- import scala.concurrent.Future
- import scala.io.StdIn
- import scala.language.postfixOps
- object Main extends App {
- def print(x: Any): Unit = {Thread.sleep(50); println(s"${LocalDateTime.now()}: $x")}
- def dangerousMethod(): Unit = {
- print("Dangerous method started")
- Thread.sleep(3000)
- throw new InterruptedException("Disaster happened!")
- print("Dangerous method finished")
- }
- def test(): Unit = {
- print("Test started")
- try {
- dangerousMethod()
- } catch {
- case th: Throwable => print(s"Throwable: $th")
- }
- print("Test finished")
- }
- test()
- print("Press ENTER to finish")
- StdIn.readLine()
- }
- // Output:
- // 2018-08-19T18:51:14.145: Test started
- // 2018-08-19T18:51:14.198: Dangerous method started
- // 2018-08-19T18:51:17.248: Throwable: java.lang.InterruptedException: Disaster happened!
- // 2018-08-19T18:51:17.298: Test finished
- // 2018-08-19T18:51:17.348: Press ENTER to finish
- //
- // Process finished with exit code 0
- // Conclusion: it's OK, Throwable matches all exceptions
- // 2. InterruptedException in try/catch-nonfatal pattern:
- case NonFatal(e) => print(s"Throwable: $e")
- // Output:
- // 2018-08-19T18:52:14.530: Test started
- // 2018-08-19T18:52:14.584: Dangerous method started
- // Exception in thread "main" java.lang.InterruptedException: Disaster happened!
- // at ru.mitrakov.self.sandbox.Main$.dangerousMethod(Main.scala:25)
- // at ru.mitrakov.self.sandbox.Main$.test(Main.scala:32)
- // at ru.mitrakov.self.sandbox.Main$.delayedEndpoint$ru$mitrakov$self$sandbox$Main$1(Main.scala:39)
- // at ru.mitrakov.self.sandbox.Main$delayedInit$body.apply(Main.scala:12)
- // at scala.Function0.apply$mcV$sp(Function0.scala:34)
- // at scala.Function0.apply$mcV$sp$(Function0.scala:34)
- // at scala.runtime.AbstractFunction0.apply$mcV$sp(AbstractFunction0.scala:12)
- // Conclusion: it's OK, NonFatal doesn't catch fatal errors
- // 3. Now let's convert method to async:
- def dangerousMethod() = Future { ...
- // Output (Enter pressed):
- // 2018-08-19T18:53:52.009: Test started
- // 2018-08-19T18:53:52.163: Dangerous method started
- // 2018-08-19T18:53:52.163: Test finished
- // 2018-08-19T18:53:52.213: Press ENTER to finish
- //
- // Process finished with exit code 0
- // Conclusion: it's OK, program had been finished before the error was thrown
- // Output (Enter NOT pressed):
- // 2018-08-19T18:54:13.302: Test started
- // 2018-08-19T18:54:13.457: Dangerous method started
- // 2018-08-19T18:54:13.457: Test finished
- // 2018-08-19T18:54:13.507: Press ENTER to finish
- // java.lang.InterruptedException: Disaster happened!
- // at ru.mitrakov.self.sandbox.Main$.$anonfun$dangerousMethod$1(Main.scala:25)
- // at scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.java:12)
- // at scala.concurrent.Future$.$anonfun$apply$1(Future.scala:654)
- // at scala.util.Success.$anonfun$map$1(Try.scala:251)
- // at scala.util.Success.map(Try.scala:209)
- // at scala.concurrent.Future.$anonfun$map$1(Future.scala:288)
- // Conclusion: it's interesting: we got stack trace even though we used try/catch instead of recover
- // 4. OK, let's use recover pattern for async code:
- dangerousMethod().recover {
- case NonFatal(e) => print(s"Throwable: $e")
- }
- // Output:
- // 2018-08-19T19:06:22.646: Test started
- // 2018-08-19T19:06:22.843: Dangerous method started
- // 2018-08-19T19:06:22.845: Test finished
- // 2018-08-19T19:06:22.895: Press ENTER to finish
- // java.lang.InterruptedException: Disaster happened!
- // at ru.mitrakov.self.sandbox.Main$.$anonfun$dangerousMethod$1(Main.scala:25)
- // at scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.java:12)
- // at scala.concurrent.Future$.$anonfun$apply$1(Future.scala:654)
- // at scala.util.Success.$anonfun$map$1(Try.scala:251)
- // at scala.util.Success.map(Try.scala:209)
- // at scala.concurrent.Future.$anonfun$map$1(Future.scala:288)
- // Conclusion: it's OK, NonFatal doesn't catch fatal errors
- // 5. Let's recover ALL exceptions:
- dangerousMethod().recover {
- case th: Throwable => print(s"Throwable: $th")
- }
- // Output:
- // 2018-08-19T18:57:00.851: Test started
- // 2018-08-19T18:57:01.004: Dangerous method started
- // 2018-08-19T18:57:01.005: Test finished
- // 2018-08-19T18:57:01.055: Press ENTER to finish
- // java.lang.InterruptedException: Disaster happened!
- // at ru.mitrakov.self.sandbox.Main$.$anonfun$dangerousMethod$1(Main.scala:25)
- // at scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.java:12)
- // at scala.concurrent.Future$.$anonfun$apply$1(Future.scala:654)
- // at scala.util.Success.$anonfun$map$1(Try.scala:251)
- // at scala.util.Success.map(Try.scala:209)
- // at scala.concurrent.Future.$anonfun$map$1(Future.scala:288)
- // Conclusion: WTF?!?!? Throwable doesn't catch fatal errors either!!!
- // 6. WTF? Maybe recover doesn't work? Let's change an exception type:
- throw new RuntimeException("Exception happened!")
- // Output:
- // 2018-08-19T18:57:45.040: Test started
- // 2018-08-19T18:57:45.195: Dangerous method started
- // 2018-08-19T18:57:45.196: Test finished
- // 2018-08-19T18:57:45.246: Press ENTER to finish
- // 2018-08-19T18:57:48.258: Throwable: java.lang.RuntimeException: Exception happened!
- // Conclusion: now it's OK, exception was catched
- // Summary:
- // 1) "case th: Throwable" catches ALL exceptions in sync code
- // 2) "case th: Throwable" does NOT catch all exceptions in async code
- // 3) use "NonFatal" in sync code with try/catch pattern: all fatal errors must be propagated outside
- // 4) use "NonFatal" in async code with "recover" pattern too
- // 5) no need to recover using "case th: Throwable" => it will NOT catch fatal errors!
- // 6) if a fatal error in ASYNC code is thrown in try/catch pattern => it will still be propagated, when the time comes up!
- // but be careful: it will happen "in background", whereas the main execution flow may be anywhere!
- // 7) don't throw fatal errors manually: leave them to JVM
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement