In Java, is using throws Exception instead of throwing multiple specific exceptions good practice?
No, absolutely not. You should specify what exceptions you're going to throw so the caller can do the right thing with each one. If you don't, "throws Exception" gets passed up the chain, and the best the callers can do is printStackTrace() and die.
Update: To counter some of the "what if I override the method" objections, I'd go a bit further and say that any time you have a package that throws exceptions (as opposed to passing up an exception from a caller), you should declare an exception class in that package. Thus, if you're overriding my "addToSchedule() throws ScheduleConflictException", you're perfectly able to subclass ScheduleConflictException to do what you need.
What makes sense for a library such as Spring MVC, which needs to be open enough to fit all sorts of different use cases, does not necessarily make sense for you to follow when writing a specific application. This is one of those cases.
If you are referring to classes such as the Controller
interface which as a method signature such as
handleRequest(HttpServletRequest request, HttpServletResponse response)
throws Exception
This is likely because, from the perspective of the Spring classes which call into your Controller (such as DispatcherServlet
), they don't care what type of Exception your code calls - library code such as DispatcherServlet
only needs to know that this class may throw an Exception and therefore is capable of handling Exception in the general case.
In other words, DispatcherServlet
doesn't need to know what specific type(s) of Exception your Controller may throw - it's going to treat any of them as an "error". This is why the method signature is throws Exception
.
Now, the API authors could have made the signature use a custom exception type as SpringMvcException
, but that would only have the effect of forcing you to handle any checked exception types in your handleRequest
method and simply wrap them, which is tedious make-work boilerplate code. So, since pretty much everything with Spring is designed to make it as easy and lightweight for you to integrate with as possible, it's easier for them to specify that the interface method merely throws Exception
.
Here's the problem with throwing specific exceptions... Suppose someone extends your class and wants to override your method. Suppose their new implementation needs to throw a different type of exception. (How would you ever be able to predict what exceptions an overriding method might need to throw?) The person writing the overriding method only has two choices: 1) handle the exception himself (likely a bad choice), or 2) wrap the real exception in one of the allowed exception types and re-throw.
But option 2 has two problems. First, when you dump your exceptions to your log files, you'll get long ugly chains of nested exceptions. More importantly, you'll lose your ability to catch specific exceptions. For example, suppose the overriding method calls another method that talks to the database and throws a DeadlockException if the resulting SQL caused a deadlock. The overriding method has to catch this exception, wrap it in one of the allowed types, and rethrow. This makes it impossible for code further up the stack to catch and detect the DeadlockException.
Your question ultimately gets into the heart of the debate about checked versus unchecked exceptions. You can Google and find lots of arguments for both sides of the debate. I think that ultimately, if you believe in checked exceptions, you should be very explicit about what exceptions a method throws. If you don't like checked exceptions, you should declare every method to throw Exception. I fall in the latter camp.
By the way, for people who don't like checked exceptions, I don't like the idea of using RuntimeException's everywhere. The problem is that you'll likely need to incorporate a 3rd party library that uses Exception's rather than RuntimeException's. Then, your code will have to catch all Exception's from the library and wrap them in RuntimeException's. That creates a mess.
So, if I were starting a Java project from scratch again, I'd just declare every method to throw Exception.