15

I use assertions in Java in a standard way, having them turned on in my IDE. So they are not part of production release. Lately I have been seeing code examples with throw new AssertionError() and I started thinking about the situation where AssertionError should be used instead of assertion.

My guess is that main difference is the optionality of asserts so they don't slow down the production performance and so they can occur quite often in the code, but fixing hardly reproducible bugs reported from users is harder.

For AssertionError, the exact opposite applies.

I also find AssertionError more practical in places in code where the execution should not get, instead of using assert false //We should not be here. Especially if the return value is required. For example:

int getFoo(AnEnum a){
    if (a == AnEnum.ONE)
       return bar();
    else if (a == AnEnum.TWO)
       return SOME_VALUE;
    //else
    assert false; //throw new AssertionError();
    return -1; //not necessary when usin AssertionError
}
  • Is my reasoning correct?
  • What are the other differences/use cases/best practices/limitations of either approach?
  • In regards to providing a description in the AssertionError - Should it be provided or is the mere fact that it is an Error (and of assertion type) enough to be more or less sure that stack trace will be provided in case of found bugs?
6
  • 8
    How often are your assertions actually slow? Personally I like to keep my seat-belt when I'm driving in the real world, rather than only when learning :) (In fact, it's much more important to fail fast in production code than in test code - if you keep going having arrived at an invalid state, you may well wipe real production data.) Consider only removing assertions when you have evidence that they're slowing your program down in a significant way. Commented Feb 26, 2014 at 21:12
  • Basically you are correct. Although some want assertions removed from production code since invalid behavior is viewed as better than outright application failure. And it's probably a good idea to provide at least a basic error description with the AssertionError, so that first-level debugging can be done without having to dig through the source files (and in case some bozo only reports the error message, without stack trace). Commented Feb 26, 2014 at 21:21
  • 1
    @JonSkeet But you could just leave assertions on for that part of the code. With AssertionError you don't have any option, it's thrown even if assertions have been deliberately disabled. Commented Aug 1, 2014 at 18:40
  • @HotLicks You can give a reason code with the assert false "Should not be reached" as well, so that does not distinguish between assert false and throw AssertionError(). Commented Aug 1, 2014 at 18:43
  • Your example is not valid if getFoo is publicly reachable, according to the Java technote "Programming With Assertions" Commented Aug 1, 2014 at 19:16

2 Answers 2

8
+125

I would advise against throwing AssertionErrors directly. If you choose to rely on AssertionErrors for checking invariants, pre/post conditions, state conditions, etc. you're still better off using regular assertions with the "-ea" flag turned on in production as well.
The reason is that the assertions mechanism (other than being optimized at the compiler level) gives you a chance to turn on or off all assertions at once. Even if you can't think of a reason to do that now, if you come across a reason in the future, just consider that you'll have to go over all your throw new AssertionError(...) type code and surround it with a nasty if clause. You get the picture.
Just as you wouldn't want a magic number hard coded into many places in your code, and would probably use a constant instead, you shouldn't infect your code with many duplications (i.e. the throw new AssertionError(...) part).

Another word about assertions though. I believe that you should think twice before relying on assertion errors in production code. The reason is that an AssertionError is very generic. It has a message and a cause, but that's pretty much it.
Consider instead using specific RuntimeException subclasses that will convey more information both by being of a specific class more related to the problem, as well as by carrying actual data related to the problem.
As a simple example, consider a case you mentioned in your question where there's some part of the code that you don't expect to reach. An assertion or an AssertionError would convey the fact that you reached some unexpected code, but not much more. Using a specific RuntimeException could also deliver the state of the local variables and parameters of the method at that point in time. You could argue that this is doable with setting the message of the assertion or AssertionError to contain this information, but this does not work when using automatic error logging/handling mechanisms. Such mechanisms can handle unexpected behaviors using the visitor pattern on the different sub classes of RuntimeException you're using to check unexpected behavior (by handle I also mean fail-fast, not necessarily recovery).

Sign up to request clarification or add additional context in comments.

1 Comment

I agree largely with your assessment (probably more than with the answer I gave), however the answer I've written is from Sun/Oracle documentation. So I can only conclude that according to Technote it is OK, if it wasn't allowed, the constructors should have been hidden. Besides that, choosing between assert false and new Error for unreachable code (where the first one is not seen as an exit point) is choosing between two evils. I agree with you that the error is bad, but having to use return null or similar is equally bad.
7

In the technote "Programming With Assertions: Control Flow Invariants" the following code is given:

void foo() {
    for (...) {
      if (...)
        return;
    }
    assert false; // Execution should never reach this point!
}

But the following note is given as well:

Note: Use this technique with discretion. If a statement is unreachable as defined in the Java Language Specification, you will get a compile time error if you try to assert that it is not reached. Again, an acceptable alternative is simply to throw an AssertionError.


You may not expect an AssertionError to be thrown when assertions are turned off. As AssertionError constructors are public, and since there is likely no substitution for AssertionError(String message, Throwable cause), I guess that you should expect them even if they are turned off.


Throwing an AssertionError on unreachable code (i.e. without any real expression to be evaluated) will never slow down the code, as Jon Skeet suggested, so it won't hurt with regards to performance.


So in the end throwing the AssertionError seems OK.

2 Comments

Only found the comment after generating the bounty, other answers welcome, of course.
I thought that a more descriptive exception class name than AssertionError was CoderMalfunctionError. Alas, that refers to the charset encoder rather than the coder in front of the keyboard! ;-)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.