<html><head><style id="css_styles" type="text/css"><!--blockquote.cite { margin-left: 5px; margin-right: 0px; padding-left: 10px; padding-right:0px; border-left: 1px solid #cccccc }
blockquote.cite2 {margin-left: 5px; margin-right: 0px; padding-left: 10px; padding-right:0px; border-left: 1px solid #cccccc; margin-top: 3px; padding-top: 0px; }
a img { border: 0px; }
li[style='text-align: center;'], li[style='text-align: center; '], li[style='text-align: right;'], li[style='text-align: right; '] { list-style-position: inside;}
body { font-family: 'Segoe UI'; font-size: 12pt; }
.quote { margin-left: 1em; margin-right: 1em; border-left: 5px #ebebeb solid; padding-left: 0.3em; }
--></style></head><body><div>I very much disagree with this position, so I will make a case for checked exceptions:</div><div><br /></div><div>1) Without checked exceptions, using exceptions for alternative outcomes as part of the contract of an API would no longer be possible. This is because adding a new exception to the API would no longer be a breaking change. Documentation is not going to save you here. Effectively, exceptions would have only two uses left (like in other languages): fatal JVM breaking errors and to signal mistakes that could have been prevented by the programmer. Using them to signal unpreventable errors would be highly suspect and likely quickly be considered a bad practice.</div><div><br /></div><div><span>In other languages (but also in some Java API's that use runtime exception to signal unpreventable errors) the compiler cannot help you with these alternative outcomes as it isn't even required to specify them as part of your API. It helps you with the return value, but not for any other outcomes. These other outcomes will now have to guessed, gleaned from the documentation (if it is up to date), or by doing manual code mining (of the called function and all the functions it calls). Worse, these outcomes can change in later releases without any warning as they're non-breaking changes.</span><br /></div><div><br /></div><div>2) API's without checked exceptions will <span>necessarily become more cluttered than their counterparts with checked exceptions. They would have to return wrappers or unions or special values to enforce proper use. API design like this prevents easily deferring the handling of rare occurrences higher up the call chain with standard idioms to keep the current code path clean and to the point.</span></div><div><br /></div><div></div><div><span>3) Removing checked exceptions now would break the **design** of many current API's, making them dangerous to use without the checks and balances that were present when they were designed.</span><br /></div><div><br /></div><div><span>4) Earlier design decisions to exclude checked exceptions from new idioms and API's were a mistake that should be rectified not doubled down upon. A large part of the momentum against checked exceptions comes from the clumsy way that checked exceptions must be handled while using these new features that were essentially </span><span>incompatible with existing </span><span>Java. Even with the current status quo, it is possible to design API's that do allow checked exceptions in combination with functional programming, it is just cumbersome to design these API's without a dedicated union type (for exceptions). They either support only one checked exception or some limited number. Their use is however as transparent as API's that do not support checked exceptions.</span><br /></div><div><br /></div><div>5) The fact that the value of checked exceptions is hard to recognize or cumbersome for beginners or non-Java developers should not have any bearing on language design.</div><div><br /></div><div>Checked exceptions differentiate between the common preventable programming errors and essential business logic. The difference between a runtime exception (leaving out Error) and a checked exception is that one can only occur in incorrect code, while the other can occur even in correct code. One indicates a preventable programming mistake and the other a missed path in your logic. Throwing these on the same heap will effectively reduce the usefulness of all exceptions to programming mistakes (and fatal errors) only.</div><div><br /></div><div>6) If anything, I think there should be way to promote runtime exceptions to checked exceptions within certain modules. This would allow API / library designers the option to have the compiler check their code for missed documentation and missing logic even for what externally would be a runtime exception. This would be especially useful during initial design and also later refactoring as the incredibly useful compiler checks for checked exceptions could be extended to proper use and propagation of runtime exceptions within that module.</div><div><br /></div><div>--John</div><div><br /></div>
<div><br /></div>
<div>------ Original Message ------</div>
<div>From "Remi Forax" <<a href="mailto:forax@univ-mlv.fr">forax@univ-mlv.fr</a>></div>
<div>To "Nathan Reynolds" <<a href="mailto:numeralnathan@gmail.com">numeralnathan@gmail.com</a>></div>
<div>Cc "amber-dev" <<a href="mailto:amber-dev@openjdk.org">amber-dev@openjdk.org</a>>; "amber-spec-experts" <<a href="mailto:amber-spec-experts@openjdk.java.net">amber-spec-experts@openjdk.java.net</a>>; "Ron Pressler" <<a href="mailto:ron.pressler@oracle.com">ron.pressler@oracle.com</a>></div>
<div>Date 12/11/2022 08:58:57</div>
<div>Subject Retiring Checked Exceptions Was: Throwing Functions</div><div><br /></div>
<div id="x9d362d73cbfa429"><blockquote cite="839324466.44117145.1668239937777.JavaMail.zimbra@u-pem.fr" type="cite" class="cite2">
<div style="font-family: arial, helvetica, sans-serif; font-size: 12pt; color: #000000"><div>[promoted to amber-spec-experts]<br data-mce-bogus="1" /></div><div><br data-mce-bogus="1" /></div><div>I think we should tackle this problem at its core and retire the notion of checked exceptions</div><div><br data-mce-bogus="1" /></div><div>The written are on the wall since quite some time, but we have not yet acknowledge it.</div><div><br data-mce-bogus="1" /></div><div>Let's recap the issue and the clues pointing in that direction.<br data-mce-bogus="1" /></div><div><br data-mce-bogus="1" /></div><div>I believe the first straw can be tracked back to the inability of the type system to create a type variable containing the union of exceptions when generics where introduced in Java 5.<br /></div><div>It's the reason why there is no ThrowableConsumer, as an example, imagine that a stream can declare a checked exception Stream<T, E> and a user call map() that takes a ThrowableFunction,<br data-mce-bogus="1" /></div><div>we need a way to express that the resulting stream is that combine the exceptions of the original stream and the exceptions that may be raised by calling the function of map.<br data-mce-bogus="1" /></div><div><br data-mce-bogus="1" /></div><div> Stream<T, E extends Exception> --> map(ThrowableFunction<T, R, F extends Exception>) --> Stream<R, E | F><br data-mce-bogus="1" /></div><div><br data-mce-bogus="1" /></div><div>Or perhaps from the beginning of Java, adding a checked exception to a "throws" colors the function the same way the keyword async or Rust lifetime type information color a function [1]. Adding a checked exception to a function is not a backward compatible change.<br data-mce-bogus="1" /></div><div><br data-mce-bogus="1" /></div><div>So we have some of idioms that beginners need to internalize to try workaround checked exceptions,<br data-mce-bogus="1" /></div><div>- The oldest is i think, Thread.currentThread().interrupt() which allows to silence an InterruptedException at the price of continuing to execute the code until the next blocking call</div><div>- UncheckedIOException and IOError that both wrap an IOException into an unchecked exception allowing tunneling of checked exceptions ; wrapping an IOException and unbundle it later.<br data-mce-bogus="1" /></div><div>- Unsafe.rethrow (this one was retired)<br data-mce-bogus="1" /></div><div>- the unfamous rethrow using erasure to see a checked exception as an unchecked exception<br data-mce-bogus="1" /></div><div> static <T extends Throwable> AssertionError rethrow(Throwable cause) throws T {<br /> throw (T) cause;<br /> }<br />- IntelliJ has changed the default try/catch snippet to instead of calling printStackTrace() to throw a RuntimeException wrapping the exception.<br data-mce-bogus="1" /></div><div> This simple change is i believe the best change to Java in the recent years (perhaps toes to toes with records), at least now the code of my students does not print the stack trace and resume its course when an exception occurs.<br /></div><div> try {<br data-mce-bogus="1" /></div><div> ...<br data-mce-bogus="1" /></div><div> } catch(FooException e) {<br data-mce-bogus="1" /></div><div> throw new RuntimeException(e);<br data-mce-bogus="1" /></div><div> }</div><div><br data-mce-bogus="1" /></div><div>Also no language presented as potential successor of Java, neither Scala nor Kotlin have checked exceptions, because functions with checked exceptions do not compose.<br data-mce-bogus="1" /></div><div>If Java wants to be the next Java, we will have to drop checked exceptions at some point.<br data-mce-bogus="1" /></div></div></blockquote><font face="arial, helvetica, sans-serif"><div id="x9d362d73cbfa429">I don't see the relevance of what other languages are doing with their own agenda's. There is no need to drop checked exceptions, they just need to be an integral part of the whole. Removing them doesn't make Java the next Java, it just makes it yet another language with slightly different syntax that succumbed to a vocal minority that values simplicity over safety.</div><br /></font><blockquote cite="839324466.44117145.1668239937777.JavaMail.zimbra@u-pem.fr" type="cite" class="cite2"><div style="font-family: arial, helvetica, sans-serif; font-size: 12pt; color: #000000"><div>The good news is that seeing all exceptions as unchecked exceptions is a backward compatible change, "throws" can still be supported for documentation purpose, the compiler can emit a warning instead of an error if there is no catch corresponding to a checked exception and allow everyone to catch any exceptions in the code.<br /></div></div></blockquote><font face="arial, helvetica, sans-serif"><br /></font><blockquote cite="839324466.44117145.1668239937777.JavaMail.zimbra@u-pem.fr" type="cite" class="cite2"><div style="font-family: arial, helvetica, sans-serif; font-size: 12pt; color: #000000"><div><span><br /></span></div><div><br data-mce-bogus="1" /></div><div>I think we should recognize that the idea of checked exceptions was a good idea on paper but not a good one in practice and work to retire the concept of checked exceptions from Java.</div><div><br data-mce-bogus="1" /></div><div>Rémi<br data-mce-bogus="1" /></div><div><br data-mce-bogus="1" /></div><div>[1] https://journal.stuffwithstuff.com/2015/02/01/what-color-is-your-function/<br data-mce-bogus="1" /></div><div><br /></div><hr id="zwchr" data-marker="__DIVIDER__" /><div data-marker="__HEADERS__"><blockquote style="border-left:2px solid #1010FF;margin-left:5px;padding-left:5px;color:#000;font-weight:normal;font-style:normal;text-decoration:none;font-family:Helvetica,Arial,sans-serif;font-size:12pt;"><b>From: </b>"Nathan Reynolds" <numeralnathan@gmail.com><br /><b>To: </b>"amber-dev" <amber-dev@openjdk.org><br /><b>Sent: </b>Saturday, November 12, 2022 5:47:10 AM<br /><b>Subject: </b>Throwing Functions<br /></blockquote></div><div data-marker="__QUOTED_TEXT__"><blockquote style="border-left:2px solid #1010FF;margin-left:5px;padding-left:5px;color:#000;font-weight:normal;font-style:normal;text-decoration:none;font-family:Helvetica,Arial,sans-serif;font-size:12pt;"><div dir="ltr"><div>I am sorry if I am very late to the discussion. Consumer, Function, Predicate, and Supplier don't allow for throwing checked exceptions. This feature is needed in many cases. What about adding a variant that allows for throwing checked exceptions? For example, a ThrowableConsumer could be defined as such...</div><br /><div>public interface ThrowableConsumer<T, E extends Throwable></div><div>{</div><div> void accept(T t) throws E;</div><div>}</div><br /><div>A method that receives this as a parameter could be defined as such...</div><br /><div>public <E extends Throwable> void process(ThrowableConsumer<T, E> consume) throws E</div><div>{</div><div> ...<br /></div><div>}</div><br /><div>The compiler takes care of ensuring the checked exception is dealt with in the caller to process().</div></div><br /></blockquote></div></div></blockquote></div>
</body></html>