Why should assertions not be used for argument checking in public methods?

Informally, argument checking and assertions serve different purposes:

  • Argument checking is to detect situations when the person calling your method does something incorrectly, while
  • Assertions are used to detect situations when you do something incorrectly.

Essentially, when you assert a condition

assert val < total;

the check conveys the following plain-English thought to the readers of your code: "I checked my code, and according to my reasoning, I am certain that val will always be less than total".

When you check an argument val, on the other hand,

if (val >= total) throw new InvalidArgumentException("val");

your code says that "the caller has forgotten to ensure that the val is less than total".

These are two different thoughts, so it is natural to employ two different ways to convey them in your code.


As per programming with Assertions

Argument checking is typically part of the published specifications (or contract) of a method, and these specifications must be obeyed whether assertions are enabled or disabled. Another problem with using assertions for argument checking is that erroneous arguments should result in an appropriate runtime exception (such as IllegalArgumentException, IndexOutOfBoundsException, or NullPointerException). An assertion failure will not throw an appropriate exception.


The intent of assertions is to check your program logic -- an assertion failure is a "Stop everything -- there's a bug!" indication. In particular, an assertion failure indicates "there's a bug here", but "here" is somewhere internal to your code, and the cause of the failure can only really be determined by examining your code (which the user of your API cannot and should not be expected to do).

When you get bad data across an API, you want to indicate "Hey! You gave me bad data!" IllegalArgumentException and its kin are the way to indicate that.

(But note that there's nothing wrong with using assertion checks on parameters within your code -- where you're not supporting a truly "public" API that will be used by people outside your team.)

But this does bring up another point: To the extent reasonable/possible, you should "catch" internal exceptions of the IllegalArgumentException ilk that may occur due to your own bugs and convert them into FatalError exceptions or some such, so the user of your API isn't led to go looking for a bad parameter on his part when there's a bug in your code.

(Also note the distinction here between public -- the Java keyword -- and "public interface" -- meaning some interface that is made available as a "formal" API to be used by individuals outside your programming team. It's the latter case we're worried about here.)