Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What to put in the throws clause of an interface method?

Suppose I have interface I and two classes A and B that implement it. The implementation of method f of this interface in A throws one set of exceptions and the implementation in B throws another set. The only common ancestor of these exceptions is java.lang.Exception. Is it reasonable to declare f throwing java.lang.Exception in this case? Any other alternatives?

The reason why I am asking is that on the one hand java.lang.Exception seems too general to me and one the other hand listing all exceptions seems impractical considering possible other implementations.

Example:

interface I {
    void f() throws Exception;
}

class A implements I {
    public void f() throws IOException {}
}

class B implements I {
    public void f() throws InterruptedException {}
}
like image 359
vitaut Avatar asked Nov 26 '10 08:11

vitaut


2 Answers

The reason for using an interface is to abstract away the implementation details.

By throwing these exceptions, you're exposing implementation details that probably should be abstracted away.

Perhaps it would be best to define a new exception. Then each implementation of f() would catch the exceptions it knows about and throw the new exception instead so you'd have:

interface I {
    void f() throws MyException;
}

class A implements I {
    public void f() throws MyException {
         try {
             ...
         } catch (IOException e) {
             throw new MyException(e);
         }
    }
}

class B implements I {
    public void f() throws MyException {
         try {
             ...
         } catch (InterruptedException e) {
             throw new MyException(e);
         }
    }
}

By wrapping the implementation exception, you're still exposing it to the caller and that can bite you when you're calling remote methods. In those cases you need to do more work to return useful information in a generic way.

Edit
There seems to be a bit of a dispute going on about the correct approach.

When we call f(), we'll need code like:

I instanceOfI = getI();
try {
    instanceOfI.f();
}
catch ( /* What should go here ? */ )

It comes down to what is a good Exception class to put in the catch block.
With OP's original code we could catch Exception and then maybe try to see which subclass we have, or not depending on requirements. Or we could individually catch each subclass but then we'd have to add catch blocks when new implementations throw different exceptions.

If we used Runtime exceptions it would come to much the same thing except that we could alternatively defer the exception handling to a caller method without even giving the possibility of exceptions any thought.

If we used my suggestion of using a new, wrapped exception then this means we have to catch MyException and then try to see what additional information is available. This essentially becomes very like just using an Exception, but requires extra work for the limited benefit of having a bespoke exception that can be tailored to the purpose.

like image 200
Adrian Pronk Avatar answered Oct 19 '22 17:10

Adrian Pronk


This seems a bit backward. You should be throwing exceptions that are relevant and possibly specific to your interface, or not at all. Change the implementations to wrap a common Exception class (although not Exception itself). If you can't deal with this you may want to wrap the Exceptions in the implementations with a RuntimeException.

like image 3
Armand Avatar answered Oct 19 '22 17:10

Armand