Reputation: 547
Let say I have this interface A that is implemented by multiple vendors:
interface A
{
void x();
void y();
}
However, I want vendors to be able to throw exceptions to signal something has failed and potentially the method could thrown a RuntimeException
. In each case, the code that calls these methods should handle the failure and continue. Just because 1 vendor throws an NPE, I don't want the system to come crashing down. Instead of leaving it up to the person calling the method (or really down the line maintainence), I would like to make sure each call will catch all exceptions by declaring each method as:
void x() throws Exception;
but this is generally bad practice (PMD doesn't like it and generally I agree with the rule for concrete methods) so I wonder is this an exception to the rule or is there a better way?
Let me be clear, I'm looking for a solution where the caller of the interface is forced to handle all exceptions (including RuntimeException
s).
To further detail my environment, all of this is running within an OSGi framework. So each vendor packages their code in a bundle and OSGi will handle all exceptions to prevent the entire system from crashing. What I'm really looking at are OSGi service interfaces that will be called by some core bundle. What I want to make sure is that when I iterate through all of the services, one service doesn't throw an NPE and stop the process that is executing. I want to handle it more gracefully by catching all exceptions thrown from the service so the other provided services are still managed.
Upvotes: 6
Views: 12790
Reputation: 6515
You could implement your interface in an abstract class that uses the template method pattern to catch and wrap RuntimeExceptions with a custom exception. However, there is no way to enforce that the vendors use the abstract class (other than documentation).
class MySeviceException extends Exception{
public MySeviceException() {}
public MySeviceException(String msg) { super(msg); }
public MySeviceException(Throwable cause) { super(cause); }
public MySeviceException(String msg, Throwable cause) { super(msg, cause); }
}
interface A
{
void x() throws MySeviceExceptionException;
void y() throws MySeviceExceptionException;
}
class ABase implements A
{
public final void x() throws MySeviceExceptionException {
try {
doX();
} catch(RuntimeException ex) {
throw new MySeviceExceptionException(ex);
}
}
public final void y() throws MySeviceExceptionException {
try {
doY();
} catch(RuntimeException ex) {
throw new MySeviceExceptionException(ex);
}
}
public abstract void doX() throws MySeviceExceptionException;
public abstract void doY() throws MySeviceExceptionException;
}
Upvotes: 1
Reputation: 96424
Creating a throws clause, even with a custom exception type, is not really an answer here. You are always going to have things like NPEs. Even if you specify to the vendors that all exceptions must be wrapped in your custom exception type there are going to be cases where somebody makes a mistake and an NPE gets through. If it wasn't for mistakes you wouldn't have NPEs.
Adding "throws Exception" is a bad idea in a lot of cases, but in some cases it works out. In frameworks like Struts and JUnit you can add "throws Exception" without a problem because the framework allows for it. (JUnit wouldn't be very useful if the first exception thrown made the test suite halt.)
You could design the system so that calls to vendor code happen in specific modules that get plugged into the system and which have exception-handling taken care of by the system, similar to how Actions work in Struts. Each Action can throw anything, there's an exception handler that logs what went wrong. That way the business logic that calls into vendor APIs wouldn't have to be bothered with useless exception-catching boilerplate, but if something goes wrong the program doesn't exit.
Upvotes: 1
Reputation: 591
Depending on your JVM settings, any method has the ability to throw a RuntimeException whether you declare it as throwing Exception or not. Catching/handling RuntimeExceptions is generally a bad practice. While there are some limited cases where this behavior could be required, RuntimeExceptions are primarily an indicator that there is something wrong with the code, rather than the usage of the product. Of course, a major downside to catching RuntimeExceptions (especially if you're ignoring them) is that things could be blowing up in your system and you have no idea that it's happening...then all of a sudden, your system spits out completely invalid data, or crashes anyway from some other reason, making it more difficult to track down the root cause.
See Sun/Oracle's tutorial about exceptions
http://download.oracle.com/javase/tutorial/essential/exceptions/runtime.html
To answer the question, unless you know exactly what Exception derivative you can expect to be throwing, you're pretty much stuck throwing Exception, though I have major doubts as to the usefulness of throwing the generic Exception class, unless you only care about logging out the stack trace and such so that you know it happened? If you're trying to robustly handle the Exception without knowing what kind of Exception it is, then you probably won't be very successful in handling it properly or even well-enough.
Upvotes: 1
Reputation: 17945
I agree with PMD - declaring that you throw generic Exception
s is ugly. I think it is better to
Recent versions of Java allow you to chain exceptions. For example, if you get a NullPointerException ex
while parsing a File f
with an external library, you would want to catch it and rethrow it as, say, a new FileParsingException("error parsing " + f + ": " + ex.getMessage(), ex);
Upvotes: 1
Reputation: 20800
Create your own Exception class ie. MySeviceException
and throw it from the interface. The idea here is to throw meaningful exceptions so don't be afraid of creating many custom exception classes if that provides most readability and maintainability for your purposes. You can catch the vendor detailed exceptions in the downstream and wrap them as your custom exception so that the upstream flow does not have to deal with vendor specific exceptions.
class MySeviceException extends Exception{
public MySeviceException() {}
public MySeviceException(String msg) { super(msg); }
public MySeviceException(Throwable cause) { super(cause); }
public MySeviceException(String msg, Throwable cause) { super(msg, cause); }
}
interface A
{
void x() throws MySeviceExceptionException;
void y() throws MySeviceExceptionException;
}
As a rule of thumb never catch Errors
, always catch Exceptions
and deal with it!
Upvotes: 9
Reputation: 1627
I would avoid placing the exception throw in the interface because of limitations that you force on implementers. If I must throw an exception by implementing your interface, it will make mockups for testing more difficult.
If something goes wrong in the code that implements your interface, that should be the concern of the programmer of the implementing class.
Upvotes: 1
Reputation: 308938
Vendors can certainly throw RuntimeException to their heart's content, because they're unchecked. That means you don't have to add the throws
clause to the interface.
It also means that clients won't have any warning from the interface definition, and the compiler won't enforce a required try/catch. The only way they'll know is to read your Javadocss.
You can create a custom exception that extends java.lang.Exception
; that's a checked exception. You'll have to add it to the throws clause; the compiler will enforce a try/catch around those methods; your clients will have to handle the problem.
Upvotes: 2