The behavior in Java and C++ is just a different philosophy of what exceptions mean, that is what I was trying to say. The semantics of an exception in these languages is that functions should either return a simple type or throw an exception if they are unable to return that type for whatever reason (be it a bug, an unmet precondition, a temporary error, an unmet postcondition, etc).
Exceptions are not extraordinary events, and it is certainly never appropriate to stop execution because some exception was raised: the program itself is supposed to, at the right level, specify what should happen when an exception is encountered.
The difference between different levels of error, such as fatal errors vs others, is captured by the type of the exception itself.
This all has little to do with Java's checked exceptions support. That is a feature that is supposed to help with verification that the program indeed specifies what to do when an exception happened, for certain classes of errors that are considered more likely to occur in production. C#, which learned from both C++ and Java, doesn't include these, but still has the same semantics for exceptions.
> Exceptions are not extraordinary events, and it is certainly never appropriate to stop execution because some exception was raised: the program itself is supposed to, at the right level, specify what should happen when an exception is encountered.
Exceptions are being used for errors, and that's fine, I just don't consider them actual exceptions because, for example, you expect certain operations to be able to fail and you should handle that failure gracefully. In Rust errors are a separate concept that can be part of the return value, but in Java and C++ (that "different philosophy") errors are also just exceptions and you're expected to know which ones happen in the course of normal operation in order to handle them.
I know in JavaScript I sometimes use try/finally (without catch) for things that throw exceptions that are indeed fatal for my function, and then something higher up can catch errors thrown by that function if it's not quite fatal anymore. But it feels annoying to have to "handle exceptions" when I should be handling expected errors instead, and writing code that contains no unexpected errors. (TypeScript at least makes that easier than it otherwise would be for vanilla JavaScript.)
Again, you're just shoe-horning in your preconceived ideas about how errors should be handled into a different language.
The philosophy of Java and C# especially* is that software should be resilient to errors in production. It doesn't matter if one function for one request with some obscure parameter failed because of a network failure or because of a bug that led to an NPE when that parameter was encountered. What matters is that all other requests that don't have that bug should continue running and not impact users unnecessarily.
So, at some points in my code, I need to handle any possible exception, and decide how to continue from that point. I also need to properly clean up resources and so on regardless of whether I encountered a bug in a subcomponent or an external failure.
Now sure, I probably don't want to be writing "catch (NullPointerException) { ... }", while I may occasionally want "catch (IOException e) {....}" . So there is some difference, but that is where the type system comes in (and the oh-so-hated checked exceptions feature).
* C++'s philosophy is the worse here, of course: programs that have bugs are not valid C++ so they don't even discuss them. Rust's "any bug should crash your program as soon as possible", while still very strange to me, is of course much better.
Java just needs better language constructs for checked exceptions to make them easier to deal with. It seems like the OpenJdk team is finally moving towards looking at making them better though.
Exceptions are not extraordinary events, and it is certainly never appropriate to stop execution because some exception was raised: the program itself is supposed to, at the right level, specify what should happen when an exception is encountered.
The difference between different levels of error, such as fatal errors vs others, is captured by the type of the exception itself.
This all has little to do with Java's checked exceptions support. That is a feature that is supposed to help with verification that the program indeed specifies what to do when an exception happened, for certain classes of errors that are considered more likely to occur in production. C#, which learned from both C++ and Java, doesn't include these, but still has the same semantics for exceptions.