Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Good pattern? <X extends Exception> ... method() throws X

Some background, then some questions.

I have only recently discovered that an interface (or class) may be generic in the type of (checked) exception that its methods may throw. For example:

interface GenericRunnable<X extends Exception> {
    void run() throws X;
}

The point is if you later instantiate this with, say, IOException and invoke the run method, the compiler knows you need to either catch IOException or mark it as thrown. Better still, if X was a RuntimeException, you don't need to handle it at all.

Here's a contrived example using the above interface, but it's basically a callback and should be quite common.

public <X extends Exception> void runTwice(GenericRunnable<X> runnable) throws X {
    runnable.run(); runnable.run();
}
...
public myMethod() throws MyException {
    runTwice(myRunnable);
}

We're calling a generic utility method runTwice (perhaps defined in an external library) to run our own specific method with a specific checked exception, and we don't lose any information about which specific checked exception might be thrown.

The alternative would have been to simply use throws Exception on both the Runnable.run method and the runTwice method. This would not restrict any implementation of the Runnable interface but the advantage of checked exceptions would be lost. Or there could have been no throws at all, also losing the advantage of checked exceptions and potentially forcing the implementation to wrap.

Because I had never seen throws X, maybe I've missed something. Furthermore, I have seen the callback example used as an argument against checked exceptions several times without it being refuted. (This question is not interested in the pros/cons of checked exceptions.)

Is throws X generally a good idea? What are the pros and cons? Can you give some examples that either use throws X or didn't but should have?

Basically, I would like some further insight. You might comment on the following examples.

  • OutputStream throws IOException (perhaps ByteArrayOutputStream could extends GenericOutputStream<RuntimeException>)

  • Callable / Future.get

  • Commons Pool borrowObject / makeObject

(Since editing, I am not asking if these could/should have been designed differently in retrospect. Rather, would throws X be better than throws Exception.)

like image 346
user2357 Avatar asked Feb 09 '14 00:02

user2357


People also ask

Can a method throw more than one exception?

A method can throw one of several exceptions. Eg: public void dosomething() throws IOException, AWTException { // .... } This signals that the method can eventually throw one of those two exceptions (and also any of the unchecked exceptions).

How do I throw an exception list?

Using the Throws keyword Throws is a keyword used to indicate that this method could throw this type of exception. The caller has to handle the exception using a try-catch block or propagate the exception. We can throw either checked or unchecked exceptions.

How do I throw an exception in Java 8?

The most straightforward way would be to use a try-catch block, wrap the checked exception into an unchecked exception and rethrow it: List<Integer> integers = Arrays. asList(3, 9, 7, 0, 10, 20); integers. forEach(i -> { try { writeToFile(i); } catch (IOException e) { throw new RuntimeException(e); } });

Can we throw multiple exceptions in Java using throw keyword?

Java throws keyword We use the throws keyword in the method declaration to declare the type of exceptions that might occur within it. As you can see from the above syntax, we can use throws to declare multiple exceptions.


1 Answers

I use this pattern all the time, mostly for functional-style java.

Pros:

  1. You can have several flavors of a higher-order pattern like Visitor, to wit:

    interface ExceptionalVoidVisitor< E extends Exception > {
        void handleA( A a ) throws E;
        void handleB( B b ) throws E;
    }
    interface VoidVisitor extends ExceptionalVoidVisitor< RuntimeException > {}
    interface ExceptionalVisitor< T, E extends Exception > {
        T handleA( A a ) throws E;
        T handleB( B b ) throws E;
    }
    interface Visitor< T > extends ExceptionalVisitor< T, RuntimeException > {}
    
  2. Your client can declare a base exception class for all the exceptions he might throw and you end up with a fully general library.

Cons:

  1. As you've discovered, there is no way to handle an exception of generic type; you must allow it to escape.
  2. The other option is to accept a generator of E, which can be awkward for clients.
like image 147
Judge Mental Avatar answered Sep 19 '22 04:09

Judge Mental