Java Forum / General / June 2006
Interfaces and exceptions, best practice question
Jama - 02 Jun 2006 07:38 GMT Greetings,
When I build my libraries, I code to interfaces, which is clearly a best practice. When programmers then create classes that use my interfaces, they complain that the exceptions they want to throw are not defined in my signature. For example:
public interface myInterface { public void instantiateThisMethod(); }
is no good. People want interfaces like:
public interface myInterface { public void instantiateThisMethod() throws Exception; }
This gives the implementing programmer flexibility to throw any exception they want. So now, all my interfaces have "throws Exception" tacked on the end of every signature.
Is this a bad idea? What's the proper approach to defining exception handling with interfaces from a best practices point of view?
Thanks, J
Tobias Schröer - 02 Jun 2006 10:40 GMT Hi,
Jama schrieb:
> Greetings, > [quoted text clipped - 19 lines] > Is this a bad idea? What's the proper approach to defining exception > handling with interfaces from a best practices point of view? IMO, throws Exception is not a very good practise. It forces you to explicitly catch all Exceptions, including RuntimeExceptions, which may not be wanted. In your case, I'd say, you define a own Exception class that can be used by programmers to encapsulate their own Exceptions:
<code> public class MyException extends Exception { public MyException (String message) { super(message); } public MyException (String message, Exception cause) { super(message, cause); } } public interface MyInterface { public void instantiateThisMethod() throws MyException; } </code>
In this way, users of you interface know what they must catch (checked exception MyException).
However, if you define an interface, you should also define what exceptions are thrown and in which cases a method will throw a checked or a runtime exception, and of what type that exception will be. Programmers will have to follow that contract.
Tobi.
chris brat - 02 Jun 2006 11:00 GMT > However, if you define an interface, you should also define what > exceptions are thrown and in which cases a method will throw a checked > or a runtime exception, and of what type that exception will be. Are you saying include the runtime exceptions (those extending java.lang.RuntimeException) in the throws clause too? Not necessary.
Tobias Schröer - 02 Jun 2006 11:44 GMT chris brat schrieb:
>>However, if you define an interface, you should also define what >>exceptions are thrown and in which cases a method will throw a checked >>or a runtime exception, and of what type that exception will be. > > Are you saying include the runtime exceptions (those extending > java.lang.RuntimeException) in the throws clause too? Not necessary. No, that was not what I meant. But you can define what runtime exceptions should be thrown, e.g. NullPointException, if the arguments are null or IllegalArgumentException, if the arguments exceed the allowed value boundaries. Those things you can define in the javadoc. However, programmers can throw any other runtime exception they want. But IMO it is a good advice to follow those definitions (though they could not be forced) and users know what to expect from a method.
Tobi
seb666fr2@yahoo.fr - 02 Jun 2006 11:09 GMT > Greetings, > [quoted text clipped - 15 lines] > This gives the implementing programmer flexibility to throw any > exception they want. In this case, the use of RuntimeException (by the implementing programmer ) is better because you do not have to specify it in the throws clause.
> So now, all my interfaces have "throws Exception" tacked on the end of > every signature. > > Is this a bad idea? If there is no reason for an abstract method to throw one or more specific exception, the use of RuntimeException by the implementing programmer seems really better.
> What's the proper approach to defining exception handling with interfaces > from a best practices point of view? http://www.onjava.com/pub/a/onjava/2003/11/19/exceptions.html
P.S: sorry for my bad english. :-)
Chris Uppal - 02 Jun 2006 11:39 GMT > When I build my libraries, I code to interfaces, which is clearly a > best practice. When programmers then create classes that use my > interfaces, they complain that the exceptions they want to throw are > not defined in my signature. That's a fundamental problem, which is inherent to the way Java uses interfaces and checked exceptions. A throws clause is a promise (to the caller of the method) that it will /NOT/ throw anything except the indicated exceptions (plus unchecked ones). Not having a throws clause at all is a blanket promise not to throw (checked) exceptions.
Personally, I have come to doubt the value of this kind of promise (or, more accurately, come to doubt the value of having the compiler police it so relentlessly), but that's the way Java works, so that's what we have to live with.
So the question is, what kind of promise is it appropriate to impose on the people implementing your interfaces ? It's a tricky design question. On the one hand (as every user of Java's IO classes knows), having too many throwable exceptions is a serious pain for the user of the interface. On the other hand the people implementing the interfaces want as much freedom as possible. It's your job to balance the conflicting interests.
I would tend to favour the users of the classes, myself. Unless the interface is one that has an inherent (i.e. visible to any /user/ of the interface) failure mode, then don't permit it to fail with a checked exception. If it /does/ have such a failure mode (which is rather common, admittedly), then as Tobias has already suggested, define your own exception class (which can be subclassed by interface implementers) and declare that. If the developers still complain then remind them that exceptions can be chained, and otherwise ignore them ;-)
Also, don't forget the value of unchecked exceptions. There is nothing wrong with using them -- provided you do it with discretion. They are appropriate for anything that the user of the interface shouldn't be /forced/ to handle on every call. That broad class of events includes failure modes which should be found and eliminated by testing.
Whatever you do, don't declare "throws Exception" !
-- chris
Ed Kirwan - 02 Jun 2006 13:34 GMT > failure mode, then don't permit it to fail with a checked exception. If it > /does/ have such a failure mode (which is rather common, admittedly), then as > Tobias has already suggested, define your own exception class (which can be > subclassed by interface implementers) and declare that. If the developers > still complain then remind them that exceptions can be chained, and otherwise > ignore them ;-)
> -- chris Ooo, 'eck, I was about to make a bit of a tit of myself there. Might as well post it for humility's sake.
I was about to take issue with the ancient and noble Chris and say that it's no good advising to declare an interface with a method which throws your own exception class, in the hope that interface implementors can subclass that exception and throw their own, because, as the interface method declares a specific exception, then this is the only type that users of the interface implementations will see: they won't see subclasses.
I thought this was like passing a super-class to a method declared as receiving a subclass: the method only sees the sublcass, and you have to instanceof to see what super-class was actually passed in.
But I was wrong.
The code snippet below is prints, "I'm doing something really special."
Which now makes me see exception handling in a new light: polymorphism-unfriendly. It's just another type of instaceof. Every time a new interface implementation adds a new exception subclass, then all users may be impacted (not necessarily, but it's possible).
Another nail in the coffin of exception-handling. (Perhaps that's too strong a phrase. "Another exception for exception-handling?")
class SpecialException extends Exception { void doSpecial() { System.out.println("I'm doing something special"); } }
class ReallySpecialException extends SpecialException { void doReallySpecial() { System.out.println("I'm doing something really special"); }
}
interface Munge { public void hej() throws SpecialException; }
public class Test implements Munge { public static void main(String[] args) { Munge munge = new Test(); try { munge.hej(); } catch (ReallySpecialException e) { e.doReallySpecial(); } catch (SpecialException e) { e.doSpecial(); } }
public void hej() throws SpecialException { throw new ReallySpecialException(); } }
 Signature www.EdmundKirwan.com - Home of The Fractal Class Composition.
Download Fractality, free Java code analyzer: www.EdmundKirwan.com/servlet/fractal/frac-page130.html
Chris Uppal - 03 Jun 2006 12:03 GMT > the ancient and noble Chris <grin/>
> Which now makes me see exception handling in a new light: > polymorphism-unfriendly. It's just another type of instaceof. Every time > a new interface implementation adds a new exception subclass, then all > users may be impacted (not necessarily, but it's possible). I think there's a lot of truth in that. The hierarchy of exceptions isn't used "normally" -- to structure sharing among polymorphically varying implementations of some protocol(s) -- but to /categorise/ the exceptions. Catch clauses are indeed "instanceof" in a short skirt and heavy makeup. What they do is decode the categories at runtime (which is not in itself a bad thing, IMO, it's just not lined up with the rest of Java's version of OO.)
Another indication that exception objects are not expected to be used as normally polymorphic objects is that you can't use an interface type in a throws declaration. (At least, I assume not -- I haven't tried it.) That's not an issue that had struck me before, though I suspect you must have faced it with your Factality tool.
-- chris
Dimitri Maziuk - 02 Jun 2006 17:00 GMT Chris Uppal sez: ... If it
> /does/ have such a failure mode (which is rather common, admittedly), then as > Tobias has already suggested, define your own exception class (which can be > subclassed by interface implementers) and declare that. Unfortunately the promise is not just to "not throw anything else", it's also to throw the declared one. That is, if you declare a method as throwing MyException, the damn thing will barf on an implementation that doesn't actually throw anything.
E.g. a data store with 3 different implementations: backed by file (IOException wrapped inside MyException), DB (SQLException, ditto), and in-memory store. Apart from an OOM (which you won't catch/wrap anyway), the last one doesn't throw -- bummer.
Dima
 Signature I'm going to exit now since you don't want me to replace the printcap. If you change your mind later, run -- magicfilter config script
Eric Sosman - 02 Jun 2006 18:10 GMT Dimitri Maziuk wrote On 06/02/06 12:00,:
> Chris Uppal sez: > ... If it [quoted text clipped - 12 lines] > ditto), and in-memory store. Apart from an OOM (which you won't > catch/wrap anyway), the last one doesn't throw -- bummer. Would you mind clarifying what you mean by "the damn thing will barf?" When an interface specifies that a method might throw MyException, neither javac nor the JVM complains about a method implementation that doesn't throw it:
public class NotSo implements DataStore { public void method() { System.out.println("in method()"); }
public static void main(String[] unused) throws MyException { DataStore store = new NotSo(); store.method(); } }
class MyException extends Exception {}
interface DataStore { public void method() throws MyException; }
 Signature Eric.Sosman@sun.com
Patricia Shanahan - 02 Jun 2006 22:00 GMT ...
> Would you mind clarifying what you mean by "the damn > thing will barf?" When an interface specifies that a > method might throw MyException, neither javac nor the > JVM complains about a method implementation that doesn't > throw it: There might be confusion with the rather annoying error message for catching a non-Runtime exception that is not declared to be thrown in try block.
try{}catch(IOException e){}
Patricia
Eric Sosman - 02 Jun 2006 22:23 GMT Patricia Shanahan wrote On 06/02/06 17:00,:
> ... > [quoted text clipped - 9 lines] > > try{}catch(IOException e){} Yeah, I suppose. But then we get to the question of whether he's calling the method through an interface reference or through a class reference:
class Tantrum extends Exception {} interface I { void method() throws Tantrum; } class C implements I { void method() {} // doesn't throw Tantrum } ... C cref = new C(); cref.method(); // can't catch Tantrum ... I iref = cref; iref.method(); // must catch Tantrum
In other words, he's gotta make a choice: use the class as itself, or use it as an implementation of an interface. Each route has its own requirements.
 Signature Eric.Sosman@sun.com
Patricia Shanahan - 02 Jun 2006 23:03 GMT > Patricia Shanahan wrote On 06/02/06 17:00,: >> ... [quoted text clipped - 30 lines] > class as itself, or use it as an implementation of an > interface. Each route has its own requirements. It's one of the few situations in which replacing the less specific with the more specific requires other changes. Usually, you can change a reference variable from an interface to an implementing class, or from a class to one of its subclasses, with no other changes in the code.
In general, I think that check was a mistake. For some blocks of code, I would like to write the catch clauses as a unit. It often can't be done, because some exception handling is needed as soon as the first call is coded, but the complete exception handling cannot be written until the try block contains at least one call that throws each significant exception.
It also makes temporarily commenting out a call during test/debug more complicated and error prone than it needs to to be, because some catch clauses may also need to be commented out.
Patricia
Chris Uppal - 03 Jun 2006 10:58 GMT > Would you mind clarifying what you mean by "the damn > thing will barf?" Changing the subject very slightly. I could've sworn I remembered Javac refusing to compile code like: void aMethod throws SomeException { // code that doesn't throw anything } but a quick check shows it quite happy. Is my memory at fault, or has something been fixed that I didn't notice.
-- chris
Eric Sosman - 03 Jun 2006 13:50 GMT >> Would you mind clarifying what you mean by "the damn >>thing will barf?" [quoted text clipped - 8 lines] > but a quick check shows it quite happy. Is my memory at fault, or has > something been fixed that I didn't notice. I suspect Patricia Shanahan has hit on the explanation. See her contributions to this thread.
 Signature Eric Sosman esosman@acm-dot-org.invalid
Dale King - 04 Jun 2006 03:56 GMT >> Would you mind clarifying what you mean by "the damn >> thing will barf?" [quoted text clipped - 8 lines] > but a quick check shows it quite happy. Is my memory at fault, or has > something been fixed that I didn't notice. Eclipse has a setting to generate an error or warning for that case and a setting to allow it for cases where it overrides or implements a method that does throw the exception.
Perhaps this is the source of your memory.
 Signature Dale King
Dimitri Maziuk - 05 Jun 2006 19:22 GMT Chris Uppal sez:
>> Would you mind clarifying what you mean by "the damn >> thing will barf?" [quoted text clipped - 8 lines] > but a quick check shows it quite happy. Is my memory at fault, or has > something been fixed that I didn't notice. Mee too, that's the reason I posted it in the first place. Looks like something's got fixed indeed.
Dima
 Signature We're sysadmins. Sanity happens to other people. -- Chris King
Dimitri Maziuk - 06 Jun 2006 04:28 GMT Dimitri Maziuk sez:
> Chris Uppal sez: >> [quoted text clipped - 13 lines] > Mee too, that's the reason I posted it in the first place. Looks like > something's got fixed indeed. Now I remember. With the above declaration, you have to catch SomeException somewhere:
try { aMethod(); } catch( SomeException e ) {}
is where it barfs. (Although "catch( Exception e )" is apparently OK. Go figure.)
Dima
 Signature I have not been able to think of any way of describing Perl to [person] "Hello, blind man? This is color." -- DPM
Patricia Shanahan - 02 Jun 2006 19:14 GMT > Greetings, > [quoted text clipped - 22 lines] > Thanks, > J I think the process should start by an effort to determine what exceptions a user of the interface should be expected to know about and handle specifically. All of those should be documented with throws clauses and @throws Javadoc comments.
It doesn't matter that some implementations may not throw all of them. It does matter that the user of the interface needs to be prepared to deal with any of them, and needs to know what they mean.
If there is a generic "something broke" condition that the interface-user cannot do much about, there may be a case for the implementer extending RuntimeException.
Throwing Exception from everything does not tell the user of the interface anything about what to prepare for, or how to interpret exceptions.
Patricia
Free MagazinesGet these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...
|
|
|