4

I am trying to add a custom throws clause to a method definied by an interface. This is not possible. How could I bypass it? Here is some code:

private void sendRequestToService(final ModuleRequest pushRequest) 
{

    ServiceConnection serviceConnection = new ServiceConnection()
    {

        public void onServiceConnected(ComponentName name, IBinder service) 
        {

            try
            {

                //some lines..

            } catch (RemoteException e)
            {
                throw new RuntimeException(new UnavailableDestException()) ;
            }
        }


    };

}

Any idea how I could throw my custom exception?

rayman
  • 20,786
  • 45
  • 148
  • 246

2 Answers2

12

There are two types of exceptions, checked and unchecked. Any Throwable is either one or the other.

An example of a checked exception is IOException; probably the most (in)famous unchecked exception is NullPointerException.

Any checked exceptions that a method may throw must be declared in its throws clause. When you @Override a method (either implementing an interface method or overriding an inherited method from a superclass), certain requirements must be met, and one of them is that the throws clause must not cause a conflict. Simplistically speaking, subclasses/implementations can throw LESS, not MORE checked exceptions.

An unchecked exception is defined as RuntimeException and its subclasses, and Error and its subclasses. They do not have to be declared in a method's throws clause.

So in this particular case, if you want to throw a CustomException in an implementation of an interface method that does not list it in its throws clause, you can make CustomException extends RuntimeException, making it unchecked. (It can also extends any subclass of RuntimeException, e.g. IllegalArgumentException or IndexOutOfBoundsException may be more appropriate in some cases).

This will allow you to compile the code as you desire, but note that the choice between choosing checked vs unchecked exception should not be taken too lightly. This is a contentious issue for many, and there are many factors to consider other than just getting the code to compile the way you want it. You may want to consider a redesign of the interface rather than having implementors throwing various undocumented unchecked exceptions not specified by the interface contract.

References

Related questions

See also

  • Effective Java 2nd Edition
    • Item 58: Use checked exceptions for recoverable conditions and runtime exceptions for programming errors
    • Item 59: Avoid unnecessary use of checked exceptions
    • Item 60: Favor the use of standard exceptions
    • Item 61: Throw exceptions appropriate to the abstraction
    • Item 62: Document all exceptions thrown by each method

Workaround "solution"

If a redesign is impossible, then wrapping your CustomException in a RuntimeException (or its subclass) will "work". That is, instead of:

// ideal solution, not possible without redesign

@Override public static void someMethod() throws CustomException {
    throw new CustomException();
}

//...
try {
    someMethod();
} catch (CustomException e) {
    handleCustomException(e);
}

You can, should you insist, do the following:

// workaround if redesign is not possible
// NOT RECOMMENDED!

@Override public static void someMethod() {
    throw new RuntimeException(new CustomException());
}

//...
try {
    someMethod();
} catch (RuntimeException e) { // not catch(CustomException e)

    if (e.getCause() instanceof CustomException) {
        handleCustomException((CustomException) e.getCause());
    } else {
        throw e; // preserves previous behavior
    }

}

It needs to be reiterated that this is NOT a recommendable technique in general. You should fix the problem at the design level if at all possible, but barring that, this is indeed a possible workaround.

Community
  • 1
  • 1
polygenelubricants
  • 376,812
  • 128
  • 561
  • 623
  • It's very clear what you said, but what if my UnavailableDestException, already extends Exception ? – rayman Aug 08 '10 at 14:02
  • Then it simply cannot be declared to be thrown from the overriding method - to declare it would be to violate the contract of the method, since callers of the method may already exist which don't catch that exception. – Avi Aug 08 '10 at 14:06
  • Any solution for this? since I already use UnavailableDestException (which extends Exception) in other cases, only way is to create new custom exception(RuntimeException) for this special case?(little bit akward) – rayman Aug 08 '10 at 14:07
  • Violating interface's contract is akward anyway. Create or wrap it in a `RuntimeException`. That's really your only resort. – BalusC Aug 08 '10 at 14:12
  • To wrap my interface contract in a RuntimeException? and throw from inside of it "throw new RuntimeException" thats what you mean? – rayman Aug 08 '10 at 14:14
  • @rayman: I believe what BalusC meant is to `throw new RuntimeException(new CustomException())` from your implementation. The created RTE "wraps" the CE, accessible through its `getCause()`. This is pretty much the only way unless you are willing to redesign (which wouldn't be a bad idea if feasible). – polygenelubricants Aug 08 '10 at 14:26
  • I tried this way, ive just replaced my throw line, with the one you suggested, and the application flew.. thats what I got: Uncaught handler: thread main exiting due to uncaught exception 08-09 09:45:29.650: ERROR/AndroidRuntime(4933): java.lang.RuntimeException: test.utils.UnavailableDestException – rayman Aug 09 '10 at 06:46
  • @rayman: That's pretty much what to expect. Now you can't `catch (UnavailableDestException e)`. You'd have to `catch (RuntimeException e)` and see if `e.getCause()` is `instanceof UnavailableDestException`. If it is, handle it, otherwise maybe you want to rethrow the `RuntimeException`. Very messy, but unless you're willing to redesign, you have no choice. – polygenelubricants Aug 09 '10 at 07:27
  • @rayman: Yes, you've made that very clear, so are you having more problems? I'm not sure what you're trying to communicate to me with the last few comments. – polygenelubricants Aug 09 '10 at 08:09
  • I just didnt understand where I should place the RuntimeException catch, coz RemoteException catch much be placed there also. – rayman Aug 09 '10 at 09:33
  • No.. since I get this error: Unhandled exception type RemoteException. I was trying to throw my custom exception from the "must-implement" RemoteException handling. I cant delete that one. – rayman Aug 09 '10 at 10:47
  • @rayman: I'm still not following you. You should adapt the techniques explained in my answer to your situation, which looks to me that you want to `catch (RemoteException e)`, and then instead of `throw new UnavailableDestException`, you `throw new RuntimeException(new UnavailableDestException())`. Then elsewhere, instead of `catch (UnavailableDestException e)`, you `catch (RuntimeException e)` and check `e.getCause()` as explained. – polygenelubricants Aug 09 '10 at 11:16
  • yes.. I got you sir, but you wrote: "Then elsewhere", where it should be? i will post you my current code(edit my question) please look at it. – rayman Aug 09 '10 at 11:29
  • @rayman: "elsewhere" is wherever you previously intent to `catch (UnavailableDestException e)` to handle it. If for some reason you don't intent to `catch` and handle `UnavailableDestException`, then just ignore it. – polygenelubricants Aug 09 '10 at 11:34
  • Yes.. I do intent to catch it. but not there.. only in the calling method, which call sendRequestToService – rayman Aug 09 '10 at 11:42
  • @rayman: So instead of `catch (UnavailableDestException e)`, `catch (RuntimeException e)` instead and so on, just like I explained in my answer. You've wrapped the `UnavailableDestException` inside a `RuntimeException`, so what you're catching is the `RuntimeException`, which can also be thrown in others ways, so you have to check and see if there's a `UnavailableDestException` in it, etc. It's messy messy messy stuff. – polygenelubricants Aug 09 '10 at 11:43
  • Problem is that it's not working since I get that error: java.lang.RuntimeException: ...UnavailableDestException and I do catch it.. so guess I miss someting.. ill take look at it all over again, and also your answers. thank you realy much.. realy kindly of you. – rayman Aug 09 '10 at 11:44
  • As an enhancement to polygenelubricants' solution I would suggest not to make your "business" exception inherit the RuntimeException, nor to use RuntimeException to wrap your exception, but rather create a "wrapper exception" as a subclass of RuntimeException. This way you can still use your business exceptions in a checked manner, and you have the possibility to catch your own wrapper exceptions specifically. (In contrast to your case, normal unchecked exceptions shouldn't be caught or only very late), so you need to differentiate between your workaround solution and "real" RuntimeExceptions. – chiccodoro Aug 09 '10 at 11:47
5

Throw a RuntimeException.

Ido Weinstein
  • 1,176
  • 8
  • 24
  • But, I would like to use this custom exception, for my own purposes – rayman Aug 08 '10 at 13:31
  • 1
    Just let it extend `RuntimeException`. Then you don't need to declare the `throws` which violates the interface's contract. – BalusC Aug 08 '10 at 13:33
  • 1
    So inherit from a RuntimeException and make a custom one. That will work. – Ido Weinstein Aug 08 '10 at 13:33
  • `RuntimeException` and really all other exceptions can wrap other exceptions/throwables as `new RuntimeException(String msg, Throwable cause)`. You can inspect these with `.getCause()` as a workaround if you don't want to create another exception type. – jocull Jun 14 '18 at 20:07