0

When performing "sanity checks" at runtime, what is the best built-in Exception to throw to indicate a logic error? InternalError is tempting, but as an Error my understanding is that it should only be use to indicate problems in the JVM itself, not application logic errors. Right now I tend to throw RuntimeExceptions, but I find that distasteful because the type is so general. Is there a more specific type I should be using?

I'm avoiding using assert for these checks because they should still be performed in production. For this reason, "you should be using assert" is not The Right Answer.

I apologize for the subjective nature of this question, but I'm hoping there are some well-known best practices that I'm just not aware of.

EDIT: Here's a good example of what I'm talking about, although certainly there are other good examples and the idea is more general:

public static void foobar(ModelObject o) {
    switch(o.getEnumProperty()) {
    case ENUMVALUE1:
        // Handle...
        break;
    case ENUMVALUE2:
        // Handle...
        break;
    default:
        // In theory, this should never be reached. The code should handle any
        // enum value it's Java-legal for the code to pass. But, if a  new
        // enum value is added and this code is not updated, this WILL be
        // reached. This is not an IllegalArgumentException because the caller
        // passed a valid value -- remember, we SHOULD handle any enum value
        // here -- but the code has not been updated. For this reason, it's an
        // "internal error" of sorts. However, there's no good "my program's
        // logic is broken" Exception that I know of built into the JRE. It is
        // this Exception that I'm looking for in this question.
        //
        // Hopefully this clarifies the question somewhat.
        throw new RuntimeException("Unhandled: "+o.getType());
    }
}

I suppose a more specific way to phrase this question would be "What kind of Exception should I throw if there is code that should never be reached, but GETS reached, in a production environment?" This is not precisely the right question, but all "sanity checks" can be "spelled" in terms of code that should never be reached, so it's close enough.

sigpwned
  • 6,957
  • 5
  • 28
  • 48
  • 6
    I can think on [`IllegalArgumentException`](http://docs.oracle.com/javase/6/docs/api/java/lang/IllegalArgumentException.html) and [`IllegalStateException`](http://docs.oracle.com/javase/6/docs/api/java/lang/IllegalStateException.html) – Luiggi Mendoza Jun 28 '13 at 03:43
  • Definitely. Both are good examples, and I use both heavily. Can you think of anything closer to a "production assert"? – sigpwned Jun 28 '13 at 03:45
  • 2
    What do you mean by a "sanity check"? – Raedwald Jun 28 '13 at 07:27
  • You're right, I'm being rather colloquial. As I'm using it, a "sanity check" is basically just a logic validation. A good example might be in a `switch` for an `enum` type. You should have a `case` for each `enum` value, and then a `default` at the end. Your `default` should throw an `Exception` because it should never be reached, since you have a `case` for each value. What should you throw if it does get reached? Not an `IllegalArgumentException`, since the argument is valid; the program just isn't handling a valid input properly. It's not an `assert`, since it should work in production. – sigpwned Jun 28 '13 at 15:43
  • Sounds like an _IllegalArgumentException_ to me... This question is weird. – jahroy Jun 28 '13 at 17:34
  • This is backwards on so many levels. How can you possibly claim the argument is 'valid' if you at the same time are throwing an exception on it? If it is indeed a valid argument then it should not raise an exception. Anyone remember the days when it was acceptable for a method to return boolean values, or even void / $this - when nothing else was to be done? Pepperidge Farm Remembers (tm). – Christoffer Bubach Nov 12 '17 at 22:13

2 Answers2

3

Java is object oriented.

Throw a SanityException or a FailedSanityCheckException.

In other words, create your own class that extends Exception.

Maybe MyCompanyException would be more appropriate than SanityException ;)

If you want it to be an unchecked runtime exception, extend RuntimeException:

class SanityException extends RuntimeException {
    public SanityException(String msg) {
        super(msg);
    }
}

It's very easy and very powerful.

Your logic can catch and handle only SanityExceptions, which is good.

I know your question asks for a built-in Exception... But if you find the built-in options distasteful because they're not specific enough, that's the exact reason to create your own (especially considering how easy it is).

Seems to me this is how Exceptions were meant to be used.

jahroy
  • 22,322
  • 9
  • 59
  • 108
  • This is a great answer, but the hypothetical `SanityException` is not part of the stock JRE. I'm trying to build a better habit for failed "sanity checks" that is portable from project to project. – sigpwned Jun 28 '13 at 15:33
  • @sigpwned it will be portable if you add the new custom `Exception` as part of your library, probably in `org.my.library.exception.SanityException`. – Luiggi Mendoza Jun 28 '13 at 15:43
  • I'm trying not to introduce a dependency on every project I work on, while still developing a good habit with respect to sanity checks. I know I could add a library with a custom `Exception` type, but I'm explicitly looking for classes in the JRE. – sigpwned Jun 28 '13 at 15:45
  • 1
    [This page](http://docs.oracle.com/javase/7/docs/api/java/lang/RuntimeException.html) lists over 50 Exceptions that extend RuntimeException. Choose one of those if you want a built-in Exception. – jahroy Jun 28 '13 at 17:32
2

There is an AssertionError throwable exception. See http://docs.oracle.com/javase/6/docs/api/java/lang/AssertionError.html

dougEfresh
  • 457
  • 2
  • 8
  • 1
    If you throw this, the entire application will stop working. – Luiggi Mendoza Jun 28 '13 at 04:37
  • 2
    @LuiggiMendoza If an assertion fails, that would be the idea, right? – Patashu Jun 28 '13 at 04:40
  • 1
    @Patashu when an `Error` is encountered, the JVM shuts down. I don't think this is what the user expects, and worse if this is an application that can have multiple users at the same time e.g. a web application. – Luiggi Mendoza Jun 28 '13 at 04:43
  • @LuiggiMendoza I agree, the application should not just stop working. – sigpwned Jun 28 '13 at 15:34
  • @Luiggi Mendoza Errors can also be caught, and it seems reasonable to catch AssertionErrors while executing code that might be outdated (like plugins). – DiddiZ Jan 12 '14 at 13:49
  • @DiddiZ you should not catch the errors. Refer to here: http://stackoverflow.com/q/352780/1065197 – Luiggi Mendoza Jan 13 '14 at 14:24
  • @Luiggi Mendoza That's not different from what I said. You may catch _selected_ errors that are likely to be thrown from an outdated plugin, and we are able to recover from, like AssertionError. – DiddiZ Jan 15 '14 at 22:58