Why does Clojure end exception checking with unchecked exceptions?

The following code demonstrates the case where a ExecutionException is thrown by an operation and Clojure wraps it with a RuntimeException .

Why is Clojure doing this? This is normal? Clojure seems to be doing something different than Java in this case. What is the idiomatic way of handling the actual exception, in this case the Exception that caused the failure?

 user=> (def f (future (Thread/sleep 10000) (throw (Exception. "hello world")))) #'user/f user=> (.get f) Exception hello world user/fn--318 (NO_SOURCE_FILE:81) user=> (.printStackTrace *e) java.lang.RuntimeException: java.util.concurrent.ExecutionException: java.lang.Exception: hello world at clojure.lang.Util.runtimeException(Util.java:165) at clojure.lang.Reflector.invokeMatchingMethod(Reflector.java:97) at clojure.lang.Reflector.invokeNoArgInstanceMember(Reflector.java:316) at user$eval320.invoke(NO_SOURCE_FILE:82) at clojure.lang.Compiler.eval(Compiler.java:6465) at clojure.lang.Compiler.eval(Compiler.java:6431) at clojure.core$eval.invoke(core.clj:2795) at clojure.main$repl$read_eval_print__5967.invoke(main.clj:244) at clojure.main$repl$fn__5972.invoke(main.clj:265) at clojure.main$repl.doInvoke(main.clj:265) at clojure.lang.RestFn.invoke(RestFn.java:421) at clojure.main$repl_opt.invoke(main.clj:331) at clojure.main$main.doInvoke(main.clj:427) at clojure.lang.RestFn.invoke(RestFn.java:397) at clojure.lang.Var.invoke(Var.java:397) at clojure.lang.AFn.applyToHelper(AFn.java:159) at clojure.lang.Var.applyTo(Var.java:518) at clojure.main.main(main.java:37) Caused by: java.util.concurrent.ExecutionException: java.lang.Exception: hello world at java.util.concurrent.FutureTask$Sync.innerGet(FutureTask.java:222) at java.util.concurrent.FutureTask.get(FutureTask.java:83) at clojure.core$future_call$reify__5684.get(core.clj:6064) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:597) at clojure.lang.Reflector.invokeMatchingMethod(Reflector.java:92) ... 16 more Caused by: java.lang.Exception: hello world at user$fn__318.invoke(NO_SOURCE_FILE:81) nil at clojure.core$binding_conveyor_fn$fn__3713.invoke(core.clj:1817) at clojure.lang.AFn.call(AFn.java:18) at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303) at java.util.concurrent.FutureTask.run(FutureTask.java:138) at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908) at java.lang.Thread.run(Thread.java:680) 
+4
source share
2 answers

According to this link, it seems that clojure is not throwing checked exceptions, so I assume that clojure will catch everything that can be thrown and wrap it: http://dev.clojure.org/display/doc/1.3

As for handling it idiomatically (?) In Java, the old rules still apply. I would check if the exception enclosed in the ExecutionException was one of the checked exceptions that I expected could occur and handle them the same way as in any other circumstances (read: emulate forced capture of a compiler attempt otherwise) . If this were not the case, I would either turn it into a run-time exception, throw it away again, or start it and swallow it, depending on the situation.

+2
source

Note that the ExcecutionException is indeed thrown - it is just that the exception is thrown and handled by Clojure.

Clojure will wrap some exceptions in a RuntimeException when it handles them. I believe this is done to avoid having to handle checked exceptions in the Clojure source code.

If you want to access the main exception then (.getCause e) should work.

+7
source

Source: https://habr.com/ru/post/1396996/


All Articles