Comment by vbezhenar
2 days ago
> Checked exceptions are for errors that are not possible to prevent. How else should the caller know which exceptions are really likely to happen?
The same way, caller can know which exceptions are really likely to happen in TypeScript, C++, Python. Or in modern Java which avoids checked exceptions anyway. By reading documentation or source code. That's perfectly fine and works for everyone.
And you highlighted one big issue with checked exceptions. You've claimed that those exceptions are "really likely to happen".
When I'm writing reading data from resource stream, the data that's located next to my class files, IO Exceptions are really unlikely to happen.
Another ridiculous example of this checked exception madness:
var inputStream = new ByteArrayInputStream(bytes);
var outputStream = new ByteArrayOutputStream();
inputStream.transferTo(outputStream); // throws IOException? wtf???
This code can throw OutOfMemoryError, StackoverflowError, but never IOException. Yet you're forced to handle IOException which doesn't happen. And that's the issue with checked exceptions.
There's no correspondence between checked exceptions and likelihood of their occurence. NullPointerException probably happens more than any checked exception. The division between checked exceptions and unchecked exceptions is absolutely arbitrary and makes sense only at caller place, never in called function signature.
> Modules absolutely achieved their primary goal: stopping libraries from accessing JDK internals without the application's knowledge. The ecosystem is slow on the uptake since split packages and access to internal APIs is endemic, but it is happening ever so slowly. I wish libraries could opt into not being part of the unnamed module.
"Slow" is an understatement. I don't see this happening at all. Last time I tried to write very simple application with modules, I spent so many hours banging my head over various walls, that I probably will not do another attempt in a foreseeable future.
There's a recent Reddit thread with some good discussion around modules where Ron Pressler took part. tl;dr: the architects acknowledge uptake outside the JDK has been slow, largely because there have always been few benefits to modules, and secondarily because build tool support is lacking (perhaps because of the first reason). At some point they may begin providing additional benefits to modularization which may help stoke demand.
https://www.reddit.com/r/java/comments/1o37hlj/reopening_the...
> The same way, caller can know which exceptions are really likely to happen in TypeScript, C++, Python. Or in modern Java which avoids checked exceptions anyway. By reading documentation or source code. That's perfectly fine and works for everyone.
This provides no automatic verification that indeed all likely error situation that can and should be handled were indeed handled. The very idea is that you have to opt in to not handle a checked exceptions. Result types don't carry a stack trace; apart from that I'm not convinced that they are interently better. In fact, I'd argue that handling a Result and an exception looks much the same in imperative code.
> When I'm writing reading data from resource stream, the data that's located next to my class files, IO Exceptions are really unlikely to happen.
Java class loaders can do anything including loading resources from the network. Which is admittedly not that common these days after the demise of applets.
> ByteArrayInputStream -> ByteArrayOutputStream
The general assumption behind IO interfaces is that the operations might fail. These two classes are oddballs in that sense. Note that the other write methods in `ByteArrayOutputStream` don't declare checked exceptions.
Since the compiler cannot prove that an exception will never be thrown (essentially due to Rice's theorem) there are always going to be false positives. The issues with checked exceptions therefore boil down to API design and API abuse.
Re Errors: the programmer cannot do anything about it and might make matters worse by trying to do so. Preventing an OutOfMemoryError relies on whole-system design so peak memory consumption is kept under control. Also the StackOverflowError, can in no way be prevented nor handled by the caller. Therefore both of them are `Error`s, not `Exception`s.
> NullPointerException probably happens more than any checked exception.
Patently untrue, as network connections break down and files cannot be accessed all the time.
The NullPointerException indicates a bug in the application. By the very reason it occurs, the current thread cannot continue execution normally. After a checked exception, it very much might. Though I would very much like to not have to handle exceptions in static initializer blocks - there is no good way to react to any problem happening there.
> "Slow" is an understatement. I don't see this happening at all.
All of this is slow-moving, I completely agree, but due to backwards compatibility concerns the ecosystem cannot be weaned off the issues that the JPMS is designed to prevent in a short time.
> This provides no automatic verification that indeed all likely error situation that can and should be handled were indeed handled.
And some people write code in Python which provides no automatic verification whatsoever.
Actually unchecked exceptions are very similar to dynamically typed languages. And that's fine. As Python and other languages proved by their mere existence: dynamic typing is not inherently bad. Sometimes it's good. I think that for error handling, it's good.
> Java class loaders can do anything including loading resources from the network. Which is admittedly not that common these days after the demise of applets.
Technically they can, but in my particular case I know very well, that my resources are residing inside of JAR file. And if that JAR file happened to reside on the failed HDD block, that's not going to be a recoverable error.
When we're talking about IO Exceptions, it's almost always failed operation which requires complete abort. It's either failed hardware, or, typically, disconnected client. Can't do much about it, other than clean up and proceed to the next client.
And the same could be said about SQL Exceptions. Like 99% of SQL exceptions are application bugs which are not going to be handled in any way other than wind up and return high level HTTP 500 error or something like that. There are cases when SQL exception should be handled, but those are rare. Yet JDBC developers decided that programmers must execute error handling rituals on every call site.
> The NullPointerException indicates a bug in the application. By the very reason it occurs, the current thread cannot continue execution normally.
That's not exactly true. In JVM, NullPointerException is absolutely well defined and you can continue execution after catching it. You might suspect, that logical application state is corrupted, but sometimes you know well that everything's fine (and in most cases you hope that everything's fine, if your Spring MVC handler threw NPE, Spring is not going to crash, it'll continue to serve requests). It's not C++ with its undefined stuff. JVM is pretty reliable when it comes to every error, including NPE, stack overflow or OOM. Latter is special, because even handling error might prove challenging, when memory allocations fail, but JVM will not hang up or crash.
> And some people write code in Python which provides no automatic verification whatsoever.
Python is a language with almost no static validation whatsoever. It would be very odd if it cared about checked exceptions. This dynamism makes big Python code bases infuriating to work with.
> When we're talking about IO Exceptions, it's almost always failed operation which requires complete abort. It's either failed hardware, or, typically, disconnected client. Can't do much about it, other than clean up and proceed to the next client.
If this is the case then the solution is to add it to the `throws` list.
> That's not exactly true. In JVM, NullPointerException is absolutely well defined and you can continue execution after catching it.
Why would I catch a NullPointerException instead of fixing my application? The JVM is indeed completely fine, but processing still cannot continue because that code simply does not exist.