3 ms·
To me, the key problem with Java’s error handling is that there’s no special consideration given to functional interfaces like Callable/Runnable/etc — so you ef
by derefr 4y ago
To me, the key problem with Java’s error handling is that there’s no special consideration given to functional interfaces like Callable/Runnable/etc — so you effectively cannot throw a checked exception from within a lexical closure passed to a Stream.map, ExecutorService.submit, etc: trying to do so gets you a compile error.
This was worked around in the design of CompleteableFutures, where the closure must cyclically capture its own future in order to be able to call .completeExceptionally on it; but that requires that every use of functional code essentially subvert Java by having a try-catch at the root of the closure’s AST that turns propagating exceptions, into, essentially, results, via a side-channel; and then the caller of CompleteableFuture.get gets the side-channel exception value thrown back at them and propagating again. Honestly a mess—and people think Golang’s little “if err != nil” checks are bad!
(What should actually be happening is “exception generic auto-deduction”: anything that accepts Callable or other functional interfaces should actually accept a (currently-impossible) type “Callable throws <T>…”; and then the list of checked error types of the instantiated object should be deduced from what the called code actually does—as Java perfectly-well knows how to do, in order to assert compiler errors about checked exceptions in the first place. This would also require you to be able to define methods that “pass along” checked exceptions without knowing what they are, though — and without just declaring you throw Throwable and thus discarding the exception typing of the callee — in order for the framework code that takes these Callables to be valid.)