Well, in more forgiving languages, such as python, you are just implicitly being "hacky" as you put it. E.g. errors - if they ever occur - will happen in runtime. Java tries to move this to compile time, making them visible. It's a tradeoff really.
No, in Python you never silentrly ignore all exceptions (well, you can, but it's a big no-no). You can just opt to not handle them, but they'll crash your program. It's a tradeoff, as I know which exceptions are likely to become a problem and which aren't, and I can choose to handle the relevant ones and let it crash in the rare case that an exception I didn't think likely occurs.
In Java, I have to handle malformed URL exceptions, even though I can see the URL in front of me, and if it's not malformed the first time, it'll never be. I see your point about runtime vs compile time, but my issue is with mandatory vs optional handling. I guess you can add "throws MalformedURLException" to let it bubble up, which is kind of the same thing, though (although you have to add all the exceptions you don't want to handle there, in that case).
> In Java, I have to handle malformed URL exceptions, even though I can see the URL in front of me, and if it's not malformed the first time, it'll never be.
That's a very good point. Malformed URL would mean that there's an error in the program. It's not an exceptional situation, like e.g. user entered malformed URL into a text field.
In these cases you should simply throw AssertionError immediately. But that still results in unnecessarily verbose code. Ideally, there should be two constructors, one that would throw an unchecked exception (URL.create(...)) and one that would throw a checked exception (URL.createOrThrow(...)). (You can create an unchecked constructor yourself.)
The reason is that Java is designed for enterprise, where "I know which exceptions are likely to become a problem and which aren't" cannot be trusted. With giant code bases and mediocre developers you kind of need to have checked exceptions or you'll have exceptions popping up in the most unexpected places.
Unfortunately, mediocre developers are perfectly capable of learning to either catch and silently ignore checked exceptions (checked exceptions actually promote this habit, which can be successfully used in other languages with exceptions) or rethrow them as runtime exceptions.
The good thing is - newer java libraries use unchecked exceptions in the vast majority of their APIs.
That's not a good thing when you are trying to write absolutely bullet-proof code that will not fall over and can recover / retry robustly.
A desktop top app is a good example of this. Network connection gone, disk full, file missing, etc. These things should not be fatal. Once the user gets back within WiFi range, empties their recycle bin, or plugs in some external storage device, the code should be able to continue sensibly.
In this situation, handling RuntimeExceptions at a high level loses all the context. Whereas, remembering to handle all the RuntimeExceptions every time you make a call is silly - they should be checked exceptions then the compiler can warn you. I've ended up wrapping a Java library to make sure that I got checked exceptions to avoid this problem.
Of course, some methods in Java throw checked exceptions some throw RuntimeExceptions. Most of these choices are sensible, but sometimes you have a hard-coded URL and you know it's not malformed. But equally, sometimes you have to catch a specific RuntimeException because that is a situation that you want to handle.
When I come across exceptions that get silently "eaten" I want to throw the dev out of a window. I've lost days of my life tracking down inscrutable bugs only to find something like this: catch ( Exception e ) { /eat it/ }
Ah, that clarifies it a bit. Python takes a more "we're all grownups here" approach, which I find suits me better. Go takes a similar approach, but I can see how Java meets a different need.
Unfortunately, all the really enterprisey Java stuff completely kills that: now that everything is injected you lose all the compile-time protection that is the point of using Java!