55

We use SonarQube to analyse our Java code and it has this rule (set to critical):

Public methods should throw at most one checked exception

Using checked exceptions forces method callers to deal with errors, either by propagating them or by handling them. This makes those exceptions fully part of the API of the method.

To keep the complexity for callers reasonable, methods should not throw more than one kind of checked exception."

Another bit in Sonar has this:

Public methods should throw at most one checked exception

Using checked exceptions forces method callers to deal with errors, either by propagating them or by handling them. This makes those exceptions fully part of the API of the method.

To keep the complexity for callers reasonable, methods should not throw more than one kind of checked exception.

The following code:

public void delete() throws IOException, SQLException {      // Non-Compliant
  /* ... */
}

should be refactored into:

public void delete() throws SomeApplicationLevelException {  // Compliant
    /* ... */
}

Overriding methods are not checked by this rule and are allowed to throw several checked exceptions.

I've never come across this rule/recommendation in my readings on exception handling and have tried to find some standards, discussions etc. on the topic. The only thing I've found is this from CodeRach: How many exceptions should a method throw at most?

Is this a well accepted standard?

2
  • 7
    What do you think? The explanation you quoted from SonarQube seems sensible; do you have any reason to doubt it? Commented Nov 26, 2014 at 21:12
  • 6
    I have written lots of code that throws more than one exception and have made use of many libraries that also throw more than one exception. Also, in books/articles on exception handling, the topic of limiting the number of exceptions thrown is usually not brought up. But many of the examples show throwing/catching multiple giving an implicit approval to the practice. So, I found the rule surprising and wanted to do more research on the best practices/philosophy of exception handling versus just the basic how-to examples.
    – sdoca
    Commented Nov 28, 2014 at 21:04

4 Answers 4

34

Lets consider the situation where you have the provided code of:

public void delete() throws IOException, SQLException {      // Non-Compliant
  /* ... */
}

The danger here is that the code that you write to call delete() will look like:

try {
  foo.delete()
} catch (Exception e) {
  /* ... */
}

This is bad too. And it will be caught with another rule that flags catching the base Exception class.

The key is to not write code that makes you want to write bad code elsewhere.

The rule that you are encountering is a rather common one. Checkstyle has it in its design rules:

ThrowsCount

Restricts throws statements to a specified count (1 by default).

Rationale: Exceptions form part of a method's interface. Declaring a method to throw too many differently rooted exceptions makes exception handling onerous and leads to poor programming practices such as writing code like catch(Exception ex). This check forces developers to put exceptions into a hierarchy such that in the simplest case, only one type of exception need be checked for by a caller but any subclasses can be caught specifically if necessary.

This precisely describes the problem and what the issue is and why you shouldn't do it. It is a well accepted standard that many static analysis tools will identify and flag.

And while you may do it according to language design, and there may be times when it is the right thing to do, it is something that you should see and immediately go "um, why am I doing this?" It may be acceptable for internal code where everyone is disciplined enough to never catch (Exception e) {}, but more often than not I've seen people cut corners especially in internal situations.

Don't make people using your class want to write bad code.


I should point out that the importance of this is lessened with Java SE 7 and later because a single catch statement can catch multiple exceptions (Catching Multiple Exception Types and Rethrowing Exceptions with Improved Type Checking from Oracle).

With Java 6 and before, you would have code that looked like:

public void delete() throws IOException, SQLException {
  /* ... */
}

and

try {
  foo.delete()
} catch (IOException ex) {
     logger.log(ex);
     throw ex;
} catch (SQLException ex) {
     logger.log(ex);
     throw ex;
}

or

try {
    foo.delete()
} catch (Exception ex) {
    logger.log(ex);
    throw ex;
}

Neither of these options with Java 6 are ideal. The first approach violates DRY. Multiple blocks doing the same thing, again and again - once for each exception. You want to log the exception and rethrow it? Ok. The same lines of code for each exception.

The second option is worse for several reasons. First, it means that you are catching all the exceptions. Null pointer gets caught there (and it shouldn't). Furthermore, you are rethrowing an Exception which means that the method signature would be deleteSomething() throws Exception which just makes a mess further up the stack as people using your code are now forced to catch(Exception e).

With Java 7, this isn't as important because you can instead do:

catch (IOException|SQLException ex) {
    logger.log(ex);
    throw ex;
}

Furthermore, the type checking if one does catch the types of the exceptions being thrown:

public void rethrowException(String exceptionName)
throws IOException, SQLException {
    try {
        foo.delete();
    } catch (Exception e) {
        throw e;
    }
}

The type checker will recognize that e may only be of types IOException or SQLException. I'm still not overly enthusiastic about the use of this style, but it isn't causing as bad code as it was under Java 6 (where it would force you to have the method signature be the superclass that the exceptions extend).

Despite all these changes, many static analysis tools (Sonar, PMD, Checkstyle) are still enforcing Java 6 style guides. It's not a bad thing. I tend to agree with a warning these to still be enforced, but you might change the priority on them to major or minor according to how your team prioritizes them.

If exceptions should be checked or unchecked... that is a matter of great debate that one can easily find countless blog posts taking up each side of the argument. However, if you are working with checked exceptions, you probably should avoid throwing multiple types, at least under Java 6.

7
  • 1
    Accepting this as the answer as it answers my question about it being a well accepted standard. However, I am still reading the various pro/con discussions starting with the link Panzercrisis provided in his answer to determine what my standard will be.
    – sdoca
    Commented Nov 28, 2014 at 21:06
  • "The type checker will recognize that e may only be of types IOException or SQLException.": What does this mean? What happens when an exception of another type is throw by foo.delete()? Is it still caught and rethrown?
    – Giorgio
    Commented Sep 28, 2015 at 11:46
  • 1
    @Giorgio It will be a compile time error if delete throws a checked exception other than IOException or SQLException in that example. The key point I was trying to make is that a method that calls rethrowException will still get the type of the Exception in Java 7. In Java 6, all of that gets merged down to the common Exception type which makes static analysis and other coders sad.
    – user40980
    Commented Sep 28, 2015 at 13:03
  • I see. It seems a bit convoluted to me. I would find it more intuitive to forbid the catch (Exception e) and force it to be either catch (IOException e) or catch (SQLException e) instead.
    – Giorgio
    Commented Sep 28, 2015 at 13:12
  • @Giorgio It is an incremental step forward from Java 6 to try to make it easier to write good code. Unfortunately, the option to write bad code will be with us for a long time. Remember that Java 7 can do catch(IOException|SQLException ex) instead. But, if you're just going to rethrow the exception, allowing the type checker to propagate the actual type of the exception wile simplifying the code isn't a bad thing.
    – user40980
    Commented Sep 28, 2015 at 13:16
26

The reason that you would, ideally, want to only throw one type of exception is because doing otherwise likely violates the Single Responsibility and Dependency Inversion principles. Let's use an example to demonstrate.

Let's say we have a method that fetches data from persistence, and that persistence is a set of files. Since we are dealing with files, we can have a FileNotFoundException:

public String getData(int id) throws FileNotFoundException

Now, we have a change in requirements, and our data comes from a database. Instead of a FileNotFoundException (since we are not dealing with files), we now throw an SQLException:

public String getData(int id) throws SQLException

We would now have to go through all code that uses our method and change the exception we have to check for, else the code won't compile. If our method gets called far and wide, that can be a lot to change/have others change. It takes a lot of time, and people aren't going to be happy.

Dependency inversion says that we really shouldn't throw either of these exceptions because they expose internal implementation details we are working to encapsulate. Calling code needs to know what type of persistence we are using, when it really should just be worried about if the record can be retrieved. Instead we should throw an exception that conveys the error at the same level of abstraction as we are exposing through our API:

public String getData(int id) throws InvalidRecordException

Now, if we change the internal implementation, we can simply wrap that exception in an InvalidRecordException and pass it along (or not wrap it, and just throw a new InvalidRecordException). External code does not know or care what type of persistence is being used. It's all encapsulated.


As for Single Responsibility, we need to think about code that throws multiple, unrelated exceptions. Let's say we have the following method:

public Record parseFile(String filename) throws IOException, ParseException

What can we say about this method? We can tell just from the signature that it opens a file and parses it. When we see a conjunction, like "and" or "or" in the description of a method, we know that it is doing more than one thing; it has more than one responsibility. Methods with more than one responsibility are hard to manage as they can change if any of the responsibilities change. Instead, we should break methods up so they have a single responsibility:

public String readFile(String filename) throws IOException
public Record parse(String data) throws ParseException

We've extracted out the responsibility of reading the file from the responsibility of parsing the data. One side effect of this is that we can now pass in any String data to the parse data from any source: in-memory, file, network, etc. We can also test parse more easily now because we don't need a file on disk to run tests against.


Sometimes there really are two (or more) exceptions we can throw from a method, but if we stick to SRP and DIP, the times we encounter this situation become rarer.

5
  • 1
    I totally agree with wrapping lower level exceptions as per your example. We do that regularly and throw variances of MyAppExceptions. One of the examples where I'm throwing multiple exceptions is when attempting to update a record in a database. This method throws an RecordNotFoundException. However, the record can only be updated if it's in a certain state, so the method also throws a InvalidRecordStateException. I think this is valid and provides the caller with valuable info.
    – sdoca
    Commented Dec 1, 2014 at 15:46
  • 1
    @sdoca If your update method is as atomic as you can make it, and the exceptions are at the proper level of abstraction, then yes, it sounds like you do need to throw two different types of exceptions, since there are two exceptional cases. That should be the measure of how many exceptions can be thrown, rather than these (sometimes arbitrary) linter rules.
    – cbojar
    Commented Dec 1, 2014 at 17:00
  • 4
    But if I have a method that reads data from a stream and parses it as it goes along, I cannot break up those two functions without reading the entire stream into a buffer, which could be unwieldy. Furthermore the code that decides how to properly handle the exceptions could be separate from the code that does the reading and parsing. When I am writing the reading and parsing code, I don't know how the code calling my code might want to handle either type of Exception, so I need to let them both through. Commented Mar 25, 2015 at 21:27
  • +1: I like this answer a lot, especially because it tackles the problem from a modeling point of view. Often it is not necessary to use yet another idiom (like catch (IOException | SQLException ex)) because the real problem is in the program model / design.
    – Giorgio
    Commented Sep 28, 2015 at 13:39
  • But I can still have business logic method where multiple business rules might fail, each throwing a different exception. For example makeMoneyTransfer() might throw NotEnoughMoneyInWallet, NonExistingRecepientAccount or OperatingOutsideOfWorkingHours, and for each exception I want different handling. And I see such exceptions as a primary example for using them (if we use checked exceptions in our apis at all), not File Not Found and similar things.
    – SadClown
    Commented May 15, 2022 at 15:33
3

I remember fiddling around with this a little bit when playing with Java a while back, but I wasn't real conscious of the distinction between checked and unchecked until I read your question. I found this article on Google pretty quickly, and it goes into some of the apparent controversy:

http://tutorials.jenkov.com/java-exception-handling/checked-or-unchecked-exceptions.html

That being said, one of the issues this guy was mentioning with checked exceptions is that (and I've personally run into this from the beginning with Java) if you keep adding a bunch of checked exceptions to throws clauses in your method declarations, not only do you have to put in a lot more boilerplate code to support it as you move to higher-level methods, but it also just makes a bigger mess and breaks compatibility when you try to introduce more exception types to lower-level methods. If you add a checked exception type to a lower-level method, then you have to run back through your code and adjust several other method declarations as well.

One point of mitigation mentioned in the article - and the author did not like this personally - was to create a base class exception, limit your throws clauses to only use it, and then just raise subclasses of it internally. That way you can create new checked exception types without having to run back through all your code.

The author of this article may not have liked this much, but it makes perfect sense in my personal experience (especially if you can look up what all the subclasses are anyway), and I bet that's why the advice you're being given is to cap everything to one checked exception type each. What's more is that the advice you mentioned actually allows for multiple checked exception types in non-public methods, which makes perfect sense if this is their motive (or even otherwise). If it's just a private method or something similar anyway, you're not going to have run through half your codebase when you change one little thing.

You did largely ask if this is an accepted standard, but between your research you mentioned, this reasonably thought-out article, and just speaking from personal programming experience, it certainly doesn't seem to stand out in any way.

5
  • 2
    Why not just declare throws Throwable, and be done with it, instead of inventing all your own hierarchy? Commented Nov 26, 2014 at 23:18
  • @Deduplicator That's kind of the reason the author didn't like the idea either; he just figured you might as well use all unchecked, if you're going to do that. But if whoever's using the API (possibly your co-worker) has a list of all the subclassed exceptions that derive from your base class, I can kind of see a little bit of benefit in at least letting them know that all the expected exceptions are within a certain set of subclasses; then if they feel like one of them is more "handleable" than the others, they wouldn't be as prone to forgo a handler specific for it. Commented Nov 26, 2014 at 23:29
  • The reason checked exceptions in general are bad karma is simple: They are viral, infecting every user. Specifying an intentional widest-possible specification is just a way to say all exceptions are unchecked, and thus avoiding the mess. Yes, documenting what you might want to handle is a good idea, for the documentation: Just knowing which exceptions might come from a function is of strictly limited value (aside from none at all / maybe one, but Java does not allow that anyway). Commented Nov 26, 2014 at 23:39
  • 1
    @Deduplicator I'm not endorsing the idea, and I don't necessarily favor it either. I'm just talking about the direction where the advice the OP was given might have been coming from. Commented Nov 27, 2014 at 0:22
  • 1
    Thanks for the link. It was a great starting place to do reading on this topic.
    – sdoca
    Commented Nov 28, 2014 at 21:07
0

Throwing multiple checked exceptions make sense when there is multiple reasonable things to do.

For example lets say you have method

public void doSomething(Credentials cred, Work work) 
    throws CredentialsRequiredException, TryAgainLaterException{...}

this violates pne exception rule, but makes sense.

Unfortunatelly, what usuallly happens are methods like

void doSomething() 
    throws IOException, JAXBException,SQLException,MyException {...}

Here there is little chance for caller to do something specific based on exception type. So if we want to nudge him into realizing that these methods CAN and sometimes WILL go wrong, throwing just SomethingMightGoWrongException is enogh and better.

Hence rule at most one checked exception.

But if your project use design where there are multiple meaningfull checked exceptions, this rule should not apply.

Sidenote: Something actually can go wrong almost everywhere, so one can think about using ? extends RuntimeException, but there is difference between "we all do mistakes" and "this talks external system and it sometimes WILL be down, deal with it".

2
  • 1
    "multiple reasonable things to do" hardly comply with srp - this point was laid out in prior answer
    – gnat
    Commented Nov 29, 2014 at 14:08
  • It does. You can DETECT one problem in one function (handling one aspect) and another problem in another (also handling one aspect) called from one function handling one thing, namely calling these two functions. And caller can in one layer of try catch (in one function) HANDLE one problem and pass upwards another and handle that one alone too.
    – user470365
    Commented Oct 12, 2015 at 7:38

Not the answer you're looking for? Browse other questions tagged or ask your own question.