loading...

I hate checked exceptions

chochos profile image Enrique Zamudio ・2 min read

I hate checked exceptions. I really do. They should have really got rid of them in Java 8. They get in the way of a lot of the new stuff; it's not a coincidence that most of the other JVM languages don't have checked exceptions.

BEGIN RANT

I have a class in which I'm overriding an abstract method:

@Override
protected Runnable createTask(Request req) {
  Response resp = new Response(Errors.CANT_CONNECT);
  if (req.getType() == Request.Something) {
    return () -> {
      try {
        oneThing(req, resp);
      } catch (IOException ex) {
        log.error("Doing something with {}", req, ex);
      } finally {
        process(resp);
      }
    };
  } else if (req.getType() == Request.SomethingElse) {
    return () -> {
      try {
        somethingElse(req, resp);
      } catch (IOException ex) {
        log.error("doing something else with {}", req, ex);
      } finally {
        process(resp);
      }
    };
  } else if (req.getType() == Request.YetAnotherThing) {
    return () -> {
      try {
        anotherThing(req, resp);
      } catch (IOException ex) {
        log.error("Doing yet another thing with {}", req, ex);
      } finally {
        process(resp);
      }
    };
  }
  return null;
}

As you can see, it's very repetitive. A block is code is basically repeated 3 times with just a very small variation. An obvious opportunity to put it elsewhere, right? Something like this looks way nicer:

private Runnable execute(BiConsumer<Request, Response> m,
        Request req, String msg) {
  Response resp = new Response(Errores.CANT_CONNECT);
  return () -> {
    try {
      m.accept(req, resp);
    } catch (IOException ex) {
      log.error(msg, ex);
    } finally {
      process(resp);
    }
  };
}

@Override
public Runnable createTask(Request req) {
  if (req.getType() == Request.Something) {
    return ejecutar(this::oneThing, req, "Doing something with {}");
  } else if (req.getType() == Request.SomethingElse) {
    return ejecutar(this::somethingElse, req, "doing something else with {}");
  } else if (req.getType() == Request.YetAnotherThing) {
    return ejecutar(this::anotherThing, req, "Doing yet another thing with {}");
  }
  return null;
}

Way nicer. Yeah.

Except I can't do this. Why not? Well, BiConsumer doesn't throw IOException, therefore I can't catch it. Also, I can't pass refs to my methods because they throw IOException.

In order to do this, I need to catch IOException inside each of my methods, only to convert it into a RuntimeException, which I can then catch in execute.

I really don't want to do that right now. So... ⌘+Z ⌘+Z ⌘+Z ⌘+Z ⌘+Z ⌘+Z ⌘+Z ⌘+Z ⌘+Z ⌘+Z

END RANT

Discussion

pic
Editor guide
Collapse
isaric profile image
Ivan Šarić

I share your hatred of checked exceptions but due to backwards compatibility Oracle can't really change that.

What I think they should have done instead is write functional interfaces that handle checked exceptions.

There is a third party oss library that does this and you might want to check out. It's called vavr.io

Collapse
chochos profile image
Enrique Zamudio Author

I've heard about vavr, it's worth a look.

Collapse
tiguchi profile image
Thomas Iguchi

You can define your own BiConsumer interface that throws checked exceptions as follows:

@FunctionalInterface
public interface CheckedBiConsumer<T, U, E extends Exception> {
    void accept(T arg1, U arg2) throws E;
}

And also define a CheckedRunnable that propagates the exception thrown by the CheckedBiConsumer:

@FunctionalInterface
public interface CheckedRunnable<E extends Exception> {
    void run() throws E;
}

That way you can leave it up to the code executing the runnable what to do with the checked exception.

Collapse
chochos profile image
Enrique Zamudio Author

Tanks for the tip! Creating the CheckedBiConsumer does the trick indeed. I can't use the second one because the code I'm extending already defines that I need to return a standard Runnable though, but that's not a problem.

Collapse
kushal256 profile image
kushal256

This library contains many useful wrappers for Lambdas and Exceptions: github.com/jOOQ/jOOL#orgjooqlambda...