PKuhn
PKuhn

Reputation: 1360

Best way to handle exceptions that can not occur

I use the following Code to build an SQL Statement that updates the values of the fields which a specific object has. My question is, since I check if the object has a specific field the exception can never occur. What is the best way to make this code more readable for example avoid using the try {} catch {} block.

 List<Field> modelFields = Arrays.asList(model.getClass().getFields());
 String updateString = "";

 for (Field field : fields) {
   if (modelFields.contains(field)) {
            try {
                updateString += " " + field.get((Object) model) + " ";
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        } else {
            updateString += " NULL ";
        }
    }

Upvotes: 3

Views: 3058

Answers (3)

YoYo
YoYo

Reputation: 9415

I agree with the answer of @JBNizet. However, maybe not in all cases you would want an exception for something that cannot occur.

I acknowledge that this is probably a little different scenario than what the OP intended, but I think still helps to put the correct answer in a broader context.

See below example.

public class App {
  enum Which {ONE, TWO};
  String on(Which which) {
    switch (which) {
      case ONE: return "This is one";
      case TWO: return "This is another";
      default: throw new IllegalStateException("Missing case: "+which.name()+" of Which");
    }
  }
}

Suppose that someone adds a 3rd Enum value THREE. This code will always compile fine, and the Editor (Netbeans / Eclipse) will also never flag this as a problem. You will only get that there is an issue during run-time.

In this case, I would even propose making sure that there is no default case defined that explicitly throws an exception. If chosen the right settings in javac or editor, it would at least be flagged much earlier. In the worst case, it would compile, but at run-time, you would still get a RuntimeException:

Exception in thread "main" java.lang.RuntimeException: Uncompilable source code - missing return statement

A little dubious ... 'Uncompilable' during runtime ...

This only works for bound switch set's that the compiler or editor should be able to figure out, meaning only Enum, and not String or int. For those cases, I likely would recommend still putting an explicit exception for uncovered case's.

Ah - and also, I am bound to say that switch cases can be avoided in a lot of scenario's ... Either by binding the case directly as a method to the Enum value (override an abstract method), or by implementing a visitor pattern.

Here is how the enum could have been re-implemented:

public class App {
  enum Which {
    ONE { @Override String on() { return "This is One"; } }, 
    TWO { @Override String on() { return "This is Two"; } }, 
    THREE { @Override String on() { return "This is Three"; } }, 
    ;

    abstract String on();
  };

  static String on(Which which) {
    return which.on();
  }

  public static void main(String[] args) {
    String result = on(Which.THREE);
  }
}

Now we have completely avoided this whole scenario ... It will now always come down to an unimplemented method detected at compile-time! Plus it is much faster too, as no switch/case lookup has to happen.

That is probably what the end-goal should be:

Prefer Compile Time Errors over Runtime Exceptions.

Upvotes: 1

Danikov
Danikov

Reputation: 725

The whole point of exceptions is that we don't expect them to occur most of the time. If building a robust, large application, you should always write to handle exceptions in a meaningful way, aborting whatever subtask the application is attempting and continuing on in a way that doesn't rely on any of the code as having succeeded.

However, if you're building something more lightweight that can get away with exiting when something goes wrong, catching and rethrowing checked exceptions as an unchecked one (typically RuntimeException) can allow you to code rapidly and not worry about checked exceptions propagating everywhere in your code.

It isn't just a case of not expecting it to happen now, but good practice going on into the future. Underlying implementations may change, code that was assumed incapable of throwing an exception may suddenly become capable due to change made in other classes. The worst thing to do is to swallow exceptions; at minimum, ensure they are printed out to logs and/or console.

Upvotes: 0

JB Nizet
JB Nizet

Reputation: 691755

If you think the exception should never happen, then throw a runtime exception wrapping the original exception:

try {
    updateString += " " + field.get((Object) model) + " ";
} catch (IllegalAccessException e) {
    throw new IllegalStateException("this should never happen: the field is supposed to be public and thus accessible", e);
}

That way, if you're wrong, or if the code evolves and what was impossible becomes possible, you'll have an exception with a clear error message and the root cause of the exception, instead of silently ignoring the error and get an unrelated error later, or worse, a valid, but incorrect result.

Upvotes: 11

Related Questions