Search code examples
javaoopexceptionthrow

When is it suitable to throw an Exception?


I've seen some code recently where the author was throwing exceptions for almost every constructor and throwing runtime exceptions for things like the code below, in a method that returns int:

if(condition){
  return 1;
}
if(condition){
  return 2;
}
if(condition){
  return 3;
}
throw new RuntimeException("Unreachable code");
// method ends here

I wouldn't have personally thrown an exception there, because I would have structured it using if and else if statements, and in this particular case your code would be fundamentally wrong for it not to satisfy one of the conditions anyway.

There are plenty of places you could throw runtime exceptions, that would never be reached if you're code is working correctly, sometimes it just seems like the author doesn't trust the code to work, in the case of the code block above. Also, every constructor could throw an exception for if it doesn't initialize correctly, but you could also structure it so that the object would be null - which you could then check for in main, for instance.

What I'm asking, basically, is when is it worth throwing an exception?


Solution

  • The point of exceptions is to communicate exceptional situations.

    In that sense: if it is absolutely unexpected that all your conditions are false in your example, and that there is also no valid return value to indicate that situation, then throwing that RuntimeException is the reasonable thing to do here; but I would probably change the message to:

    throw new RuntimeException("All conditions failed: " + some data)
    

    As said: it is about communicating; in this case to the person debugging the problem. So it might be helpful here to include the information that is required to understand why exactly all those checks turned out false.

    The point is: there is a contract for that method; and that contract should include such details. Meaning: if that method is public, you should probably add a @throws RuntimeException with a clear description.

    And it is also a valid practice to use RuntimeException for such situations; as you do not want to pollute your method signatures with checked exceptions all over the place.

    Edit: of course, balancing is required. Example: my classes often look like:

    public class Whatever {
      private final Foo theFoo;
    
      public Whatever(Foo theFoo) {
       Objects.requireNonNull(theFoo, "theFoo must not be null");
       this.theFoo = theFoo;
    

    So, there might be a NPE thrown from my constructors; yes. But: only there. All my methods can rely on the fact that all fields were initialized to non-null; and they are final, so they will always be non-null.

    Meaning: one has to stay reasonable; and "develop" a feeling for: which problems are exceptional but possible; and which ones are so impossible that you don't pollute your code all over the place to check for them.

    Finally; just to make that clear - adding exceptions is only one part of the equation. When something throws, then you need something to catch! Therefore, as said: balancing comes in. Whatever you do in your code has to "add value" to it. If your code doesn't fulfill a clear, defined purpose, then chances are: you don't need it!