Is “throws Throwable” good practice

前端 未结 9 1028
攒了一身酷
攒了一身酷 2020-12-30 21:14

In the past I\'d read tons of code with methods like:

public Object doSomething() throws Throwable {
    ...
}

Is it common practice to do

相关标签:
9条回答
  • 2020-12-30 21:25

    In some rare cases it is acceptable to throw Throwables. For example, @Around advices in Spring AOP are usually declared to throw a Throwable.

    The following example is copied verbatim from Spring AOP docs:

      import org.aspectj.lang.annotation.Aspect;
      import org.aspectj.lang.annotation.Around;
      import org.aspectj.lang.ProceedingJoinPoint;
    
      @Aspect
      public class AroundExample {
    
          @Around("com.xyz.myapp.SystemArchitecture.businessService()")
          public Object doBasicProfiling(ProceedingJoinPoint pjp) throws Throwable {
              // start stopwatch
              Object retVal = pjp.proceed();
              // stop stopwatch
              return retVal;
          }
    
      }
    

    Why is doBasicProfiling declared to throw a Throwable? Because the original method (i.e. the execution join point), might throw an Error, RuntimeException, or a checked exception. So it only makes sense to declare doBasicProfiling to throw a Throwable.

    0 讨论(0)
  • 2020-12-30 21:27

    Throwing (and catching) Throwable (or Exception) is generally bad practice because it 'blankets' any specific exceptions you might want to catch. Then you would have to resort to ugliness like below:

    public void myMethod() throws Throwable {
        if (x) {
            throw new MyException1();
        }
        if (y) {
            throw new MyException2();
        }
    }
    
    public void callingMethod() {
        try {
            myMethod();
        }
        catch(Throwable t) {
            if (t instanceof MyException1) {
                // handle exception 1
            }
            else if (t instanceof MyException2) {
                // handle exception 2
            }
            else {
                // handle other exceptions
            }
        }
    }
    

    Which is error prone (and flagged by CheckStyle as a code violation). It is much preferrable to have code like this:

    public void myMethod() throws MyException1, MyException2 {
        if (x) {
            throw new MyException1();
        }
        if (y) {
            throw new MyException2();
        }
    }
    
    public void callingMethod() {
        try {
            myMethod();
        }
        catch(MyException1 e) {
            // handle exception 1
        }
        catch(MyException2 e) {
            // handle exception 2
        }
    }
    

    Handling an exception just by calling printStackTrace() is usually not a good idea. printStackTrace() sends the stacktrace to standard error, which may not be read at all. A better option is to use the application's logging facility (like log4j) to report the exception. Even then, just logging it might no be enough.

    My rule of thumb is:

    If you can handle an exception locally, do so. For example when parsing a String as an Integer you could catch the NumberFormatException and return a default value:

    prvate int parseAmount(String amountValue) {
        int amount;
        try {
            amount = Integer.parseInt(amountValue);
        }
        catch(NumberFormatException e) {
            // default amount
            amount = 0;
        }
        return amount;
    }
    

    If you cannot handle an exception locally, consider if you should expose the exception type that is being thrown. If this type is some obscure (implementation-dependent) type, then wrapping it in your own generic exception type is probably a good idea:

    private Customer getCustomer(int customerId) throws ServiceException {
        try {
            return customerService.getCustomer(customerId);
        }
        catch(CustomerServiceSpaghettiTangledException e) {
            throw new ServiceException("Error calling the customer service", e);
        }
    }
    

    Here 'ServiceException' is a subclass of Exception created by you. Spring also offers an exception hierarchy specifically for this purpose.

    By wrapping the exception you hide the implementation details, making your service layer much simpler to use.

    If you decide to throw an exception from your method, you will need to handle it 'higher up' in the callstack. This can be a generic error page in your web application stating that something went wrong and possibly providing an error message or code. In some cases the higher level code can attempt a retry or possibly an alternative way to obtain the required result.

    0 讨论(0)
  • 2020-12-30 21:29

    Are you asking about Throwable specifically? If so, then it's not good practice. It doesn't provide any useful information to class (method) user.

    0 讨论(0)
  • 2020-12-30 21:30

    That's a loaded question. This isn't so much about exception handling as it is about code readability.

    It depends where you get your code samples from. Professionals prefer to be more specific when throwing out of a method. The main reason is that it keeps your APIs more readable. For example, if your method throws Throwable, that basically means anything could happen and your method doesn't want to deal with it, no matter what. But really, only a limited number of things could happen:

    • Whatever checked exceptions resulting from other calls you are making in your method
    • Whatever checked exceptions you are throwing on purpose based on your own assertions
    • Whatever unchecked exception you didn't plan for
    • Errors (java.lang.Error) that are more global to the JVM and the environment

    By specifically stating the exceptions you want to throw, you are telling the users of your API about what they should beware of. For example, when you use InputStream, you'll notice most methods throw at least java.io.IOException, which gives you some useful information about what you should watch for.

    When coding, as a general rule, you want to try to keep your APIs as expressive as possible. You've got essentially one line of code to show the public API of a method (i.e. its signature, annotations too I guess), so you want it completely expressive (return type, name, parameters, but also the thrown exceptions).

    As far as catching the throwables and printing the stack trace, I'd say that you should not catch the exception unless you can do something about it. Instead, let it roll up the call stack until some class catches it to do something about it. Sometimes, it may roll all the way up to your main class, which I guess would have to catch it and print the stack trace as last resort. Basically, if you can't act upon the exception, then let it go up the call stack. Also it is extremely rare that you find yourself in a situation where you should silence an exception (i.e. catch it but do nothing about it). That's usually inviting problems when comes time to troubleshoot issues.

    Here is a fun but interesting article around misuse of exception handling in general.

    0 讨论(0)
  • 2020-12-30 21:37

    Functionally, it is equivalent with throws Exception, since errors are unchecked.

    I see no reason to declare a method to throw Throwable. However, this doesn't mean that catch and printStackTrace is a good alternative.

    Usually, you want to catch throwables where you can do something sensible with them.

    Code that throws a throwable you don't expect should explode gloriously, so you can see the error and fix the bug.

    0 讨论(0)
  • 2020-12-30 21:39

    Is it common practice to do that?

    In the JDK it is rare. This is mostly used when it is not clear how to handle checked exceptions.

    What are pros & cons?

    The pros is that you get your code to compile without worrying about checked exception.s

    The cons is that exception you should be handling are being ignored.

    Isn't it better to catch and printStackTrace()?

    Unhandled exception are usually printed anyway so catching them doesn't help much.

    You should catch an exception when you can add some value by doing so and add the exception to the throws clause when you can't.

    0 讨论(0)
提交回复
热议问题