Remix.run Logo
BoppreH an hour ago

> there is nearly no magic

I agree with the rest, but there's definitely a lot of magic in Java. This is from both what features the languages makes available (many) and how the community uses them (often). I've had so many hard-to-debug issues in Java over the years due to reflection, annotations, and bytecode manipulation shenanigans.

And another positive point for Java: checked exceptions. It's verbose, but knowing exactly in which ways a function can fail is extremely helpful for building robust applications.

kccqzy 23 minutes ago | parent | next [-]

A lot of that is coding style. I’ve also seen a lot of hard-to-debug issues in Python caused by reflection, weird decorators that muck around with name-mangled symbols, and bytecode manipulation. You can even manipulate the traceback object so it’s more difficult to make sense of why the exception comes from.

It took me quite a long time to accept that the recommended unit testing library manipulates bytecode so that the exception message for `assert a == b` prints the values for both.

msluyter an hour ago | parent | prev | next [-]

I haven't really been in the java space for a while now, but I recall there being a fair bit of criticism[1][2] of checked exceptions over the years.

[1] https://www.javacodegeeks.com/2026/01/javas-checked-exceptio...

[2] https://reflectoring.io/do-not-use-checked-exceptions/

WRT magic, I've generally thought that was a result of frameworks - Spring, for example. In the past, my feeling was that these impose a sort of meta/configuration language that itself is not checkable at compile time, so you'd get weird runtime errors that are somewhat inexplicable. This was like... 2018 though, so perhaps things have improved.

BoppreH 32 minutes ago | parent | next [-]

I'd argue that checked exceptions are still worth it, even though all the problems pointed out do exist. And that's because it works to inform consumers of what a producer is doing. Haskell has the IO and Maybe monads; Java communicates the same information through IOException and other domain exceptions.

Many times I've decided to switch from one function to another, or even an entirely new library, because the checked exceptions told me that it was doing far more than I expected, and I was not comfortable introducing those new failure modes.

It's far from perfect, one still has to handle nulls and wrapped/merged exceptions, but overall I like this language feature.

voidfunc 42 minutes ago | parent | prev [-]

Checked exceptions are controversial mostly because a lot of the core APIs use them in places where it's pointless to check, like IOException.

Using them correctly can be great tho.

PaulHoule 24 minutes ago | parent | next [-]

Mostly I think they are a mistake, like in ordinary application code instead of catching close to the throw you want to do a lot of

  try {
     ...
  } finally() {
     ...
  }
to make sure things get torn down that have to be torn down and let the exception go to the top of the unit of work and probably to whatever drives the work unit. You can probably do better than logging the raw exception and moving on to the next work unit but you can do much worse. That is, you want a default "sloppy" error handling approach that's correct that you can do without thinking and avoid other kinds of "sloppy" coding encouraged by checked exception such as catching exceptions locally without doing the right thing globally.

Occasionally though I have built something really sensitive, like an authentication filter for a web site which has at least 5 ways to log in and in that I have a hierarchy of exceptions and use checked exceptions heavily to document all the ways things can go wrong and felt like "the type system really has my back here" but that is like 5% of the Java I write.

ndriscoll 16 minutes ago | parent | prev [-]

Scala's ZIO also demonstrates that they're a great idea and can be perfectly ergonomic, but you need type inference, which Java devs were resistant to for a long time (maybe still are? I remember lots of "how will I ever know what `val a = new Animal()` is???"). If you infer the exception type, they're basically invisible except for when you forget to have some place in your program to handle them, which is exactly what you want.

cavoirom 11 minutes ago | parent | prev | next [-]

I agree, to name a few:

- Annotation processing: if you know Lombok, MapStruct.

- Class loader.

- Reflection.

- Garbage collection.

theandrewbailey 32 minutes ago | parent | prev [-]

> but knowing exactly in which ways a function can fail is extremely helpful for building robust applications

I've worked on Java apps that have failed in mysterious ways that no exception could explain. Meanwhile, the overhead of having to call out certain exceptions but not others in language syntax is a bit excessive.

For example, decoding a byte array (or URL encoded form field) into a UTF-8 string means handling a theoretical UnsupportedEncodingException. What the fuck? How the hell can one have a JVM that doesn't support UTF-8? Why does my code need boilerplate that will never run because there might be some broken-ass JVM out there that that doesn't support UTF-8? How did it launch a web server, safely load all the libraries, and accept a web request, and route it to my code without blowing up? "But the encoding scheme might change..." No, it won't change. It's always going to be UTF-8. It will always be UTF-8. If it's not, let it blow up.

Horffupolde 25 minutes ago | parent [-]

Perhaps you are the trip you expected to blow up first.