1

I am developing a library for working with files and want to make it as easy to use (i.e. not having to worry about exceptions), but also as complete as possible (i.e. allow for proper exception handling).

To achieve this, I expose two methods. One that allows for normal catching of exceptions:

public void saveChecked() throws IOException, IllegalArgumentException {
    // Possibly throw an IOException or IllegalArgumentException
}

...and one that handles all exceptions using a generic Consumer<Exception>:

public void save(Consumer<Exception> handler) {
    try {
        saveChecked();
    } catch (Exception exception) {
        handler.accept(exception);
    }
}

The intention behind this is, that, if you don't need to differentiate between exceptions and just want to do one simple thing when an exception is thrown (e.g. print the stack trace, show a popup), you can just use the second version instead of having to write out a try-catch block (and making one-liners impossible).

Is this still bad practice even though the API does expose a method which allows proper exception handling for those that need it?

cegredev
  • 1,485
  • 2
  • 11
  • 25
  • 1
    Having an API throw low level exceptions (`IOException`, `IllegalArgumentException`) is a bit smelly. Perhaps create a custom exception(s), which extends from `RuntimeException`, to wrap all low level exceptions. The API would not have to declare any exception. Internally, a default error handler could just throw the custom exception(s), but a user could override the default error handler with a callback if needed. – Andrew S Jan 26 '21 at 19:45
  • I actually do have a base `RutimeException` class that most exceptions I throw myself behind the scenes inherit from, but wrapping other exceptions is exactly what I was doing beforehand and am trying to avoid, because it takes away the ability to handle different exceptions using try-catch. I also see the same problem with a default handler since it is not possible to handle all exceptions that could ever possibly be thrown and the way they are handled might differ from file to file. – cegredev Jan 26 '21 at 19:52
  • @AndrewS that's complete bunk. A method that is inherently I/O related (e.g. it is called 'saveToFile' or otherwise is specced, either via its name or its documentation, as inherently involving some sort of I/O) is of course allowed to `throws IOException`. The runtime exceptions in java.lang are meant for general purposes. Every top 50 library on github throws them, for example. – rzwitserloot Jan 26 '21 at 20:21
  • This rather sounds like a request to review working code... Which means you are on the wrong site... – GhostCat Jan 26 '21 at 20:31

1 Answers1

2

I am developing a library for working with files and want to make it as easy to use (i.e. not having to worry about exceptions), but also as complete as possible (i.e. allow for proper exception handling).

It's java. Exceptions are part of the language. Reinventing the exception system is mostly just going to lead to a bizarre library that doesn't fit in with the rest of java.

do one simple thing when an exception is thrown (e.g. print the stack trace, show a popup)

psv main is allowed to be declared as throws Exception. More generally, if you want to handle all exceptions in the same way, let the exception bubble all the way to the top, and register an exception handler e.g. via Thread.setDefaultUncaughtExceptionHandler.

If you just hate checked exceptions, you probably shouldn't be using java. However, if you somehow must go against the grain, there's always UncheckedIOException that you can throw, which makes that whole 'bubble up to the top, register an uncaught exception handler' a little bit easier.

Is this still bad practice

Yes. Writing non-idiomatic java is bad practice.

rzwitserloot
  • 85,357
  • 5
  • 51
  • 72