简体   繁体   中英

Is it okay to declare a checked exception for an exception thrown by a called method?

Consider this:

public void Do() throws Exception {

 if (blah) throw new Exception(...);

 Thingy thingy = ...;

 Foo(thingy);
}

public void Foo(Thingy thingy) throws EmptyThingyException {

   if (thingy == null || 
     thingy.isEmpty()) throw new EmptyThingyException();

  ...
}

public class EmptyThingyException extends Throwable { ... }

In this case, is it okay to not handle EmptyThingyException inside Do and declare Do like so:

public void Do() throws Exception, EmptyThingyException {

or do I have to handle EmptyThingyException inside Do and throw it back again like so:

public void Do() throws Exception, EmptyThingyException {
    try {
    } catch (EmptyThingyException empty) {
      throw empty;
    }
    ...
  }

The short answer to the question is:

Yes, it's correct to declare a checked exception thrown by a called method.

How a method achieves its purpose is an implementation detail and it shouldn't matter to the interface how much it does directly or how much it delegates to methods. The language rules about checked exceptions are carefully defined to make sure methods advertise all checked exceptions they may throw or methods they call throw (but are not handled by the method itself). Letting an unhandled exception get 'thrown through' a method is how things are supposed to work. Indeed the answer is in the name of the construct "non-local exception handling" it was conceived to take effort out of endless error handling all the way up a call chain when the only real action is "that didn't work" at some point near the start.

To align to that method, you should only catch exceptions you're going to do something about. Clean up code should be achieved with finally so the normal reasons to catch an exception are to log it and/or abandon a task at some point rather than letting the stack unwind further.

In this specific case the best answer would be to throw an IllegalArgumentException :

throw new IllegalArgumentException("thingy==null || thingy.isEmpty()");

That's unchecked and wisely so. Correct code shouldn't encounter illegal arguments and they should expect to be thrown rarely and be indicative of program flaw (either in the class, it's package or consumer code). External and user input should be validated directly and programs shouldn't rely on IllegalArgumentException .

In practice IllegalArgumentException and IllegalStateException should cover 'internal errors' meaning "You can't do this with that" or "You can't do that right now" respectively and should be commented to specify the fault.

The idea that you might sub-class those two because consumer code might respond differently to different illegal actions it might take is bodging pure and simple.

Program correctness includes that a program never makes an illegal call on some other part of the program or enters an invalid or corrupted state and exceptions only occur as a result of environmental failures that mean a program or sub-task in a program cannot be completed as intended.

if you want to do something after exception happen , then use try-catch , or you can just declare it on the method.

Beyond that, if EmptyThingyException is sub class of Exception , then it is no need to declare EmptyThingyException when you have declared Exception .

1- Declare the specific checked exceptions that your method can throw

public void foo() throws Exception { //Incorrect way
}

Always avoid doing this as in above code sample. It simply defeats the whole purpose of having checked exception. Declare the specific checked exceptions that your method can throw. If there are just too many such checked exceptions, you should probably wrap them in your own exception and add information to in exception message. You can also consider code refactoring also if possible.

2- Always catch only those exceptions that you can actually handle

catch (NoSuchMethodException e) {
   throw e; //Avoid this as it doesn't help anything
}

Well this is most important concept. Don't catch any exception just for the sake of catching it. Catch any exception only if you want to handle it or, you want to provide additional contextual information in that exception. If you can't handle it in catch block, then best advice is just don't catch it only to re-throw it.

3- Avoid using Throwable class

Throwable is the superclass of Exception and Error, as far as I know you need to use Throwable when you want to deal with both exceptions and errors, but it's definitely not your concern here, most of the java code deal with Exception and it's the way to go whenever you need to deal with checked exceptions http://docs.oracle.com/javase/tutorial/essential/exceptions/index.html .

** Well if I was you I would do something like :

public void Do() throws BlahIsFoundException{
 try {
     if (blah) throw new BlahIsFoundException(...);

     Thingy thingy = ...;

     Foo(thingy);
 } catch(EmptyThingyException exception) {
     //Handle the exception correctly, at least log it
 } finally {
     //Do some clean up if needed, for example close a database connection or free some resources.
 }
}

public void Foo(Thingy thingy) throws EmptyThingyException {

   if (thingy == null || 
     thingy.isEmpty()) throw new EmptyThingyException();

  ...
}

public class EmptyThingyException extends Exception { ... }
public class BlahIsFoundException extends Exception { ... }

Hope that helps, here are some good documents to read : http://docs.oracle.com/javase/tutorial/essential/exceptions/index.html http://howtodoinjava.com/best-practices/java-exception-handling-best-practices

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM