I’m not experienced with Java asserts but I think the answer here naturally follows from what Java asserts are:
- Code that is only run if enabled
- Disabled by default
Thus we can surmise that assertions should never be used to implement application logic: it should only be used as optional (because of the on/off feature) sanity checks/explicit assumptions. The correctness of your app (modulo bugs!) cannot depend on a runtime flag which is turned off by default.
So only use assertions to check internal assumptions (your own code only, not things that are out of your control like user input). But on the other hand you might sometimes want to use exceptions to check your assumptions; if you want to always check a certain assumption then you don’t need the on/off feature that assertions provide.
For the task of checking assumptions, it seems that assertions excel when:
The check might be costly so you want the option of disabling it
Using if-or-throw would be too much “noise” but you can bear the cost of one little assert <expr>
You want to leave a little comment which merely states something like:
// NOTE we KNOW that `x` is not null!
x.doWork();
Then the Java folks say that you should always replace that line with:
assert x != null;
x.doWork();
Or (in my opinion) if you prefer:
if (x == null) {
throw new IllegalStateException("shouldn’t be null");
}
x.doWork();
Things that follow from these principles
I think we can immediately expand on related principles (sibling answer) by using this “optional” principle (my gloss in cursive):
- use exceptions when checking parameters passed to public or protected methods and constructors
- Because you are checking things outside your code: code coming into your module
- use exceptions when interacting with the user or when you expect the client code to recover from an exceptional situation
- Because the input is from the user and has nothing to do with your code. Also assertions are not really something you are supposed to recover from.(†1)
- use exceptions to address problems that might occur
- I.e. errors that happen as a matter of course: not bugs in your code
- use assertions when checking pre-conditions, post-conditions and invariants of private/internal code
- Because it’s your own code: problems inside your own code are self-caused
- use assertions to provide feedback to yourself or your developer team
- Bugs are for developers to deal with
- use assertions when checking for things that are very unlikely to happen otherwise it means that there is a serious flaw in your application
- Key word “serious flaw in your application”
- use assertions to state things that you (supposedly) know to be true
Notes
I think this is a general opinion. See also (my bold):
Why is AssertionError a subclass of Error rather than RuntimeException?
This issue was controversial. The expert group discussed it at length, and came to the conclusion that Error was more appropriate to discourage programmers from attempting to recover from assertion failures.