Hacker News new | ask | show | jobs
by paulddraper 2380 days ago
99% of the time I want to do the same thing for IOException as I would for NoSuchElementException or a DOMException.

That said, even if typed checked exception handling is important...it quickly becomes untenable.

   Thing thing = create();
   try {
     ...
   } finally {
     cleanup(thing);
   }
You might try to abstract this

   withThing(thing -> ...)
But what if "..." potentially throws IOException? What if it potentially throws IOException or AWTException?

You have to give up all your exception type safety to make an abstraction like withThing. It's just not composable.

2 comments

    interface ThrowingConsumer<T, E extends Exception> {
        void accept(T value) throws E;
    }

    // ...

    <E extends Exception> void withThing(ThrowingConsumer<Thing,E> callback) throws E { ... }
The problems are that (a) you need to add an extra type parameter for exceptions all over the place, (b) exception unification (sum type) doesn't work generically - you can say E1 | E2 in a catch block but it's not a real type, and (c) it composes poorly with existing libraries that expect Consumer<T> throughout.

For one level deep callbacks (for resource handling and the like) it works reasonably well though.

(b) is what I had in mind as the problem.
You can always opt out of the typed checked exceptions.

    try {
        ...
    } except (IOException|NoSuchElementException e) {
        throw new RuntimeException(e);
    }
If you decide you don't want checked exceptions in your code, wrapping the exceptions at the boundaries is not a huge deal.
Or switch to a language that does that for you, like Scala or Kotlin.