41 ms·
Unchecked Java: Say goodbye to checked exceptions
- invalidname 3y agoFYI this too is already supported by Manifold...
- _ea1k 3y agoThat is referenced in the readme. :) TBH, I hadn't seen either one before today, and they both look really nice. The type-safe JSON feature in Manifold could be incredibly useful.
- invalidname 3y agoYes. It's fantastic see: https://debugagent.com/series/manifold https://debugagent.com/series/manifold
- dgellow 3y agoWhat is manifold in this context?
- invalidname 3y agoSee my reply to jsight...
- asddubs 3y agoI actually quite like checked exceptions, and miss them in other languages. My biggest gripe with exceptions is that a few calls deep, you can no longer tell whether calling something might throw or not, and what type of exception it might potentially throw.
- _old_dude_ 3y agoChecked exceptions are a leaky concept in Java. The Java type system has no union types so you can not have a generics method that abstract more than one exception. That's why Stream::map can not capture the checked exceptions properly.
- pharmakom 3y agoYes! The problem with the Java implementation of checked exceptions is the inheritance hierarchy, which encourages catching the broadest possible error.
- rozap 3y agoDefinitely they have shortcomings in Java but throwing the concept out entirely is a bummer. It creates a whole shadow type system where all bets are off.
- josephcsible 3y agoI like checked exceptions in principle too, but Java's implementation of them is so bad that I hate them there. The first major mistake is that it doesn't support exception polymorphism (e.g., I wish you could pass a comparator to Arrays.sort that throws checked exceptions, and have that call to Arrays.sort itself then throw the same checked exceptions), and the second is that the standard library makes a bunch of exceptions checked that should be unchecked (e.g., IOException from close()).
- sam_lowry_ 3y agoWhich is now commonly wrapped into UncheckedIOException.
- flerchin 3y agoNeat. Reminds me of lombok in that it really only affects compile-time and makes for cleaner code in a way that many (but not all) developers would want.
- jameslars 3y agoUgh Lombok! Literally everything it does is replaced by any competent IDE with auto-generated methods, with the added benefit of not requiring special build handling steps because the library can't play by the normal annotation processing rules. There was maybe a time Lombok made sense. It does not anymore. Death to Lombok.
- never_inline 3y agoThat's usually one time concern. Much better than having boilerplate lying around IMO.
- nabogh 3y agoDisagree. Just because the ide wrote a bunch of boilerplate for me at some point doesn't mean I can know the boilerplate is unchanged without reading a bunch of getters and setters. The mental burden of tiny classes is so much nicer to read.
- jameslars 3y agoThis is every Lombok lover's favorite strawman argument I've run into. I've been coding in Java professionally for ~20 years. I can count with zero hands the number of times I've been burned by a getter or setter getting changed into something surprising. If you really need auto-generated getters/setters/builders - Immutables [1] is a library that does it using bog standard annotation processing rules that don't require hacking your build process. [1] https://github.com/immutables/immutables https://github.com/immutables/immutables
- nnnnico 3y agoAllowing unchecked exceptions in languages without explicit error handling or the return of error values is a mistake IMO! Makes it impossible to call a function safely
- RGBCube 3y agoExactly, C++ exceptions are horrible, you never know what throws what. Java made C++ exceptions better by making them explicit, so you always know what throws. Then Kotlin came and made everything a unusable mess (don't get me wrong, I love Kotlin, just hate that it doesn't have explicit exceptions). I honestly think the best error handling strategy is employed by Zig, then Rust. they're very explicit while not getting in the way, you always know what throws what and what doesn't. Rust has a little issue though, which is that people can make their functions return `Result<T, Box<dyn Error>>` which makes handling the returned error difficult, Zig does not have any of that.
- SomeRndName11 3y agoI think the way Go does error handling is the best compromise.
- the_gipsy 3y agoIt's a successful compromise, but probably not the best. It has a huge amount of little issues that simply aren't there with FP error handling.
- kaba0 3y agoGo’s solution is like people couldn’t decide on if they should turn left, or turn right to avoid the cliff, so to make everyone happy they drove straight into it. It is literally the compiler enforced shitty error handling from C’s errno that is not even a sum type.
- vips7L 3y agoIt’s honestly the worst compromise. You can trivially ignore any error in Go and they don’t contain contextual information about the call stack.
- _ZeD_ 3y agoplease, for the love of what's good in the world... NO. checked exceptions ARE A FEATURE, a CORE ONE.
- zeedude 3y agoManifold already provides this feature: https://github.com/manifold-systems/manifold/tree/master/manifold-deps-parent/manifold-exceptions https://github.com/manifold-systems/manifold/tree/master/man... With an article having the same name as your post: https://github.com/manifold-systems/manifold/blob/master/docs/articles/unchecked.md https://github.com/manifold-systems/manifold/blob/master/doc...
- galaxyLogic 3y agoThis seems like a major improvement for Java readability as shown by the examples. What I don't like is the examples of having to use Maven or Gradle to install it. Why does that have to be so verbose, and something written in another language?
- rogerkeays 3y agoHa, yeh. At first I had the command line examples first, but everyone was going on and on about maven and stuff, so I figured that's what the audience wants. [EDIT] I moved the command line stuff back to the top of the README. XML makes my eyes bleed too...
- deleted 3y ago[deleted]
- phoe-krk 3y ago> Unchecked does not make any changes to your bytecode. This is possible because the JVM does not know about checked exceptions. It's been the compiler holding you back all this time. TIL!
- rho4 3y agoStill hoping that Java will support such a choice (compiler option) out of the box in the future. Also, without IDE support such a plugin will never gain a lot of traction.
- zeedude 3y agoManifold provides this feature and supports IntelliJ IDEA and Android Studio. https://github.com/manifold-systems/manifold/tree/master/manifold-deps-parent/manifold-exceptions https://github.com/manifold-systems/manifold/tree/master/man...
- rho4 3y agoI am using Eclipse. But will definitely keep this in mind, should I every switch to IntelliJ.
- watwut 3y agoNothing better then having to guess whether the method may throw an exception or not.
- dtech 3y agoYou already have to guess. All method calls van throw Runtime exceptions.
- code_runner 3y agonothing better than someone assuming a method can only throw a specific type of exception or won't throw at all.
- bedobi 3y agoException based error handling is so bad and unsafe that adopting functional error handling with Either, Try etc as implemented by functional addon libraries for many languages, while not yet common, in time it will become the new default even in OO languages. (just like it's been the default in functional languages for decades) Functional error handling types are much simpler, safer and more powerful. Simpler because they don't rely on dedicated syntax- they're just regular objects no different to any other object. Safer because unlike exceptions, they force callers to handle all potential outcomes, but no more. (no risk of ignoring errors and no risk of catching a higher level of error than desired, ubiquitous bugs in exception based error handling) Powerful because they support map, flatmap, applicative etc, making it easy to eg chain multiple computations together in desired ways, which is unwieldy and bug prone when using exceptions. > What is wrong about dedicated syntax It adds complexity to the language! It could be that, when learning Java, Kotlin and any other language, we learn that methods return what they say they do... and that's that. No weird dedicated syntax and magic, special treatment for returning anything other than the happy path, and the HUGE complexity that comes with it, eg the dedicated syntax itself and how it behaves, differences between checked and unchecked exceptions, hierarchies of exceptions etc etc. > Exceptions are easier But that's the point, they're not. Exceptions based error handling is unnecessary, hugely complex, doesn't compose at all, obfuscates or straight up hides what can go wrong with any given call, so leads to countless trivially preventable bugs... I could go on. And after decades of use, there's still no consensus about what exceptions should be or how they should be used. Exceptions are a failed experiment and I have no doubt that in ten years, Java, Kotlin and many other languages will acknowledge as much and move away from it the same way Joda Time outcompeted and replaced the horrible Java date and time library.
- misja111 3y agoException based error handling is unsafe when they are unchecked exceptions. Checked exceptions however are as safe as Either, Try, Monads, Applicatives or whatever. You are forced to declare them in your method signature, the caller is forced to either handle them or rethrow them + declare them as well. And I guess this is precisely why so many developers hate them; they don't like the extra work they have to do to catch all those edge conditions. This is why we see so many empty catch blocks or upcasting to Exception or even Throwable; it is laziness. I would also argue that checked exceptions are no more complex than Eithers, Try or Applicatives. Actually passing Eithers or Applicatives around everywhere can easily clutter your code as well, IMO it can be worse than checked Exceptions.
- darklycan51 3y agoCertified Try catch moment
- lucasyvas 3y agoThis is a mistake - checked exceptions and functional equivalents are the clear path forward.
- edpichler 3y agoLater you detect an error, more expensive it is to fix it.
- ars 3y agoThat's not really true. Vast majority of the time either the caller will fix it, or it simply does not need to be fixed at all it's simply passed all the way up to the top.
- nepthar 3y agoReading through the comments, I realize this may be a minority view - but I like coding for the happy path and letting exceptional states crash. I find languages like go a bit harder to parse quickly because I always have to "unwrap" the happy path from all of the mixed in error handling. I'm sure I'd get used to it eventually, but I like that unchecked exceptions in Java are now an option!
- asddubs 3y agoI'm fine with doing this on purpose, but without a system like checked exceptions, you do it without even really realizing you're doing it. Checked exceptions point out the errors and then let you decide whether it's something you should handle or let it crash. It makes for more stable software.
- code_runner 3y agoits only an illusion of stability. so many things can go wrong outside of exceptions and all it does is add mandatory lines of code (probably rethrowing as a runtime exception) to every single consumer. It pollutes everything it touches.
- bottlepalm 3y agoI didn't know Java apps were so much more stable than C# ones.
- wvenable 3y agoThe number of exceptional errors one can reasonably handle is so small to be insignificant. Aborting the current operation (which could be just one task or the whole application) is the most common result. Abort and log. Unchecked exceptions make that easy. Checked exceptions make that long and tedious and add nothing. What and where you can handle exceptions has nothing to do with where the exception is thrown. Handlers only exist at key points in the application at the start of operations where you can skip, abort, or retry.
- the_gipsy 3y agoIn practice there is a lot of paths that you don't want to "crash" on, but try the next thing etc.
- edpichler 3y agoThis dependency removes one of the best features of Java, which make others think about what happens if things go wrong.
- code_runner 3y agoonly the things that someone acknowledges may go wrong
- dtech 3y agoMost other languages agree that checked exceptions are not good by not having them. As for alternatives, Try/Result and similar monads have decent adoption even in Java, but personally I quite like the Kotlin philosophy [1] to not have generic error containers and either use runtime exceptions for errors that cannot be reasonably handled by the caller and encapsulate failures in the return type if they can. [1] https://github.com/Kotlin/KEEP/blob/master/proposals/stdlib/result.md#error-handling-style-and-exceptions https://github.com/Kotlin/KEEP/blob/master/proposals/stdlib/...
- clownvorld 3y agoThe Trouble with Checked Exceptions A Conversation with Anders Hejlsberg, Part II https://www.artima.com/articles/the-trouble-with-checked-exceptions https://www.artima.com/articles/the-trouble-with-checked-exc...
- taftster 3y agoThis is an insightful interview, thank you for the link. I'm well read up on the topic, but this interview was still great and is a good perspective on the checked/unchecked debate. The fact that Java has introduced UncheckedIOException, in my opinion, shows how some people in the Java community have come to believe that checked exceptions were a mistake (understanding that lambda forced the issue). There's probably not too much to be easily done at this point, but consideration for changing checked exceptions in the JDK to extend RuntimeException sure would be interesting.
- rogerkeays 3y agoI think this project shows how trivial it is to convert checked exception errors to compiler warnings. https://github.com/rogerkeays/unchecked/blob/f22c8cde3557de00327871b3b303f0da4ba7537b/Unchecked.java#L49 https://github.com/rogerkeays/unchecked/blob/f22c8cde3557de0... No need to change the type hierarchy. Just make it a compiler option.
- alanfranz 3y agoI don't want to remove all checked exceptions in random code, btw. Even though they're not common, it can be bad if they're unhandled in some cases. How can I know beforehand? I'd like something to soften some of them, probably in a configurable way, in some builtin interfaces btw. E.g. many IOExceptions should really be unchecked.
- macpete42 3y agocatch them at the source and return sealed classes (used like sum types) instead
- code_runner 3y agoTo the credit of the die-hard Java community, you all really seem to love and support even the most horrific syntax and awful language features. You love the pain. The rest of us are here for you... I promise software can be fun. Checked exceptions are far and away the worst part of java and I'm glad that no other language I've personally encountered have them! On a more real note, I work at a shop with a fair amount of java now and checked exceptions are definitely my biggest complaint. I hope we adopt this, I'm sure we won't, but I'm glad to see a little movement on what I feel is the crusty status quo in the java world.
- bottlepalm 3y agoAgreed, checked exceptions are awful. The idealists love them, the realest knows you can't write code up front handle every single exception case, and in most cases you aren't recovering from an exception anyways. Especially the higher the level the code is the more potential lower layers that can fail. It's just not scalable to write code up front to deal with every single case. And most programmers don't care about failure, or working around it, just success. On the other hand we do expect the unexpected and wrap failure prone code in try/catch so that we can log exceptions and keep the app moving. Figure out later if the ROI is there from enough failures to write special code to try to prevent and/or recover from a particular exception. It's pretty much the same as it is in the checked exception world just with more code - in Java people handle the exception, log it and/or rethrow, so what's the point? Idealism and poor assumptions by the language designer. Anyone have any proof that a Java app is more reliable than a C# one?
- breadwinner 3y agoOne of the biggest flaws in C#, in my experience, is lack of checked exceptions. As an example, I wrote some very good code, carefully tested it, made it work flawlessly, then suddenly it started crashing. What happened? Someone made a change in a function I was calling, and it started throwing a new exception. This would have caused a compile error in Java, not a crash. More on checked vs unchecked exceptions here: https://forum.dlang.org/thread/hxhjcchsulqejwxywfbn@forum.dlang.org https://forum.dlang.org/thread/hxhjcchsulqejwxywfbn@forum.dl...
- skissane 3y ago> Someone made a change in a function I was calling, and it started throwing a new exception. This would have caused a compile error in Java, not a crash. Not necessarily. If it started throwing a new RuntimeException, it wouldn’t have. There are also sneaky ways to throw checked exceptions without declaring them, for example using Lombok’s @SneakyThrows annotation
- breadwinner 3y agoCertainly you can intentionally break it, but then that's on you.
- skissane 3y agoA person can also accidentally break it - by adding some new code which contains a bug which causes an unchecked exception or error to be thrown (e.g. NullPointerException, ArrayIndexOutOfBoundsException, StackOverflowError, etc). Checked exceptions do nothing to protect against those kinds of mistakes, which in my personal experience are vastly more common than whatever mistakes for which they may provide some protection
- deleted 3y ago[deleted]
- kaba0 3y agoEverything can fail at every time — that’s part of the art of programming to discern which error conditions are meaningful to be included in the signature, and which are not.
- dejj 3y agoLombok’s @SneakyThrows https://projectlombok.org/features/SneakyThrows https://projectlombok.org/features/SneakyThrows
- w10-1 3y agoThe friction between the benefits of detecting errors statically, handling them quickly, and the diversity of needs for error handling cannot be avoided with any fixed policy like "unchecked only". This tool does remind us that checked exceptions in Java are a compile-time phenomenon only, so (non-compliant) compilers can be made to ignore them. Neat, but... helpful? It would certainly lock you into using the tool. Instead, we need configurable policies for error handling, where the same code can be statically analyzed much more deeply (e.g., to include unchecked exceptions) or run more leniently (e.g., when exceptions are used only for flow control). Some of this might pertain to local declarations, and some might be policies of various scopes (per VM, per-package, or per call-chain), and would probably fold in assertions and fibers/virtual threads and some OS-sensitive behaviors. The goal would be to write the code once (with full disclosure, i.e., only check-able exceptions and assertions), but to reuse the same code under different policies. Whether anyone wants to do the work of folding this into the VM as security privileges were is another question...
- smrtinsert 3y agoAgreed. I absolutely prefer checked exceptions since it forces devs and consequently business to develop requirements for possibilities. Lack of ambiguity helps me sleep at night. Potential runtime errors do not.
- riku_iki 3y agoThe issue with checked exceptions in Java is that they are not supported in java lambda syntax and library functions.
- earthboundkid 3y agoConceptually there’s not much difference between checked exceptions and multiple returns or returning a tuple with an error etc. The problem with Java is that the checked exceptions are too fine grained, so the signatures are brittle and non-composable. Everything should just throw an Exception and then use dynamic typing to figure the rest out, and then you wouldn’t have the problem that your toList method can’t compose with something that throws an unknown Exception subclass.
- vbezhenar 3y agoChecked exceptions are one of biggest mistakes Java ever made. That said, patching compiler is not something I would do. What I usually do is add unchecked exception class for every checked exception I had to "handle". So I have UncheckedIOException from standard library (handy!), UncheckedSQLException and so on and so on. Yes, it causes more code, but Java is not exactly known for brevity, so be it. At least that way is not hacky in any way and actually used by Java standard library itself, so I'd consider it "idiomatic".
- rogerkeays 3y agoYou can also rethrow checked exceptions as runtime exceptions by exploiting type erasure: public static RuntimeException unchecked(Exception e) { Exceptions.<RuntimeException>throw_checked(e); return null; } private static <E extends Exception> void throw_checked(Exception e) throws E { throw (E) e; } then you can do this: try { ... } catch (IOException e) { throw unchecked(e); } And the original exception is thrown without being wrapped. It's as though you had `throws IOException` on your method signature. This is from my original solution to the problem: https://github.com/rogerkeays/jamaica-core/blob/0cc98b114998dc80bdc3ad26f6678e6eee0a239e/src/exceptions.java#L159C5-L165C2 https://github.com/rogerkeays/jamaica-core/blob/0cc98b114998...
- vbezhenar 3y agoThere's one big problem with this approach. You can't catch checked exception if the try-block does not throw it (according to compiler). That's compiler error. So yes, you can throw IOException masking it to RuntimeException, however you can't catch it later without another gimmicks like catching Exception and checking if it's IOException (and even that check causes linter warnings in Idea, so now you need to suppress those warnings...). Throwing and catching UncheckedIOException does not have this problem.
- rogerkeays 3y agoGood point. Actually the plugin didn't handle this case either (fixed now). Thanks for the feedback.
- javajosh 3y agoLike the idea, but I probably won't use it. Yes, checked exceptions are annoying, but the correct place to fix them is the source. This compiler plugin blinds you. The ordinary ways to mitigate checked exceptions (wrapping them in unchecked exceptions) is ugly but its also explicit. Note: I will try it, because maybe I'm wrong.
- rogerkeays 3y agoYou still get warnings about checked exceptions from this plugin, so it's not entirely flying blind.
- theanonymousone 3y agoPutting aside the discussions about the necessity of checked exceptions (to which I feel unqualified to express my opinion), I believe the approach used by the OP article to remove them is not the best one: - It requires modifying compiler arguments and putting some file in the local classpath! That's really not Java-ic. Is it? - It is not transparent in the code. You cannot infer by looking at the source code that something has changed. Since some time ago I use the NoException library[0] in my Java projects which achieves the same goal but without the above-mentioned issues. It can also be used to mimic Scala's Try construct. [0] https://github.com/robertvazan/noexception https://github.com/robertvazan/noexception
- exabrial 3y agoI love the idea of this project. Just needs some IDE and possibly some verifier support! I do just want to correct a tiny piece of the readme: > a common practise is to rethrow it as a RuntimeException. The problem with this, ... is that the root cause of exceptions get hidden, This is most definitely not true. If you wrap / re-throw as a RuntimeException you will absolutely get your original stack trace.
- briffid 3y agoChecked exceptions turn out to be part of the API, meanwhile violating Liskov substitution principle and preventing some design patterns. This is because a superclass implementation might throw a checked exception, then its subclass not necessarily. However, if the caller refers the subclass instance via the superclass interface it must catch the exception, but if it refers via the subclass it must not catch, as that results in a compile error. So the point is that with checked exceptions you cannot replace an interface with any implementation, which should be possible in proper OO programming.
- Hackbraten 3y agoThat’s not a Liskov violation. Changing the compile-time type of a local variable in the scope of the call site is not substituting the implementation of the referred-to object. Those are two different things. As you correctly mentioned, if you leave the compile-time type of a variable unchanged, then assign a different object (one that belongs to a subclass that doesn’t throw the exception when you call its method) to that variable, and then call that same method, the compiler still forces you to catch. That’s the Liskov substitution.
- throwaway2037 3y agoI never forget reading the javadoc for Google Gson class com.google.gson.JsonParseException (extends RuntimeException): This exception is a {@link RuntimeException} because it is exposed to the client. Using a {@link RuntimeException} avoids bad coding practices on the client side where they catch the exception and do nothing. It is often the case that you want to blow up if there is a parsing error (i.e. often clients do not know how to recover from a {@link JsonParseException}. I have *completely* the opposite style: Throw checked for anything that can throw, except: null pointers and invalid arguments (e.g., negative port number). Why so much checked? The caller cannot hide from it. They are forced to ack it, else compiler error. At the very worst, they are free to rethrow as a wrapped RuntimeException (ugh). When I write code in C#, I always left wondering: Does this method throw an exception (ignoring null pointer and invalid arguments)? It bothers me. And, I write that as someone who really likes C# -- it's a great language for my needs. And, yes, I can appreciate that many people don't like the friction associated with checked exceptions. It does add a lot of visual bloat! Serious question: What are the alternatives that _communicate sufficiently_ through an interface? Honestly, I struggle to think of a better alternative, so I just live with it. Just like the bad old days of integer return values used to indicate error state (C-like languages), you need to check every single call -- there are no shortcuts, especially with I/O. For me, it is similar with Java and C# when writing I/O code: You need to catch and correctly handle every (checked-ish) exception.
- arein3 3y agoIn kotlin there are no checked exceptions, and I haven't missed them a bit.