I have a slight disagreement with the good people at Sun on this one, I guess. I see nothing wrong with using asserts in a particular way, even in production code.
If you ascribe to the notion of preconditions and postconditions described by Design by Contract (DbC), then when you document methods you describe the precondition that every caller must meet as well as the state that method will leave the system in if the caller does meet that postcondition.
In my way of thinking, if the caller doesn't meet the precondition, then the behavior of the method is undefined. It could throw an AssertionError, some exception, enter an infinite loop, or call System.exit(). It could do anything...that's why preconditions must be spelled out precisely in the documentation for calling that method.
The time to use Java's normal exception mechanisms are the cases where the caller meets the precondition, but due to some unforeseen circumstance your method still cannot meet its advertised postcondition (could be the failure of some other system...maybe the database has inconsistent or incoherent data for example). These circumstances are "exceptional" conditions because they should not happen (the DB should not have inconsistent or incoherent data, obviously this is the result of some bug somewhere else) and they are not the caller's fault or the fault of your method up to that point.
Exceptions are useful in this context, because you have to keep in mind that there is very little you can say for certain about the caller and what they're trying to do big-picture. Your caller could be anything in the system, and you have no idea if this is a showstopper problem for that caller or not. So the best thing to do is describe the problem as best you can and throw the exception--if the caller is in a situation where they can accomplish their task in some other way, this allows them to do that, and you have no way of knowing whether they can go about their task in some other way.
If you look at things this way, you can quickly see that it is impossible and undesirable to write an assertion for the exceptional case described above. You'd have to assert every conceivable valid state for the entire system on every other line of code. Not practical.
I'm of the opinion that it doesn't even make sense to assert in certain, specific instances that meet the above "exception" criteria...some people think, hey, I know the database has been acting up in this one particular way, so I'm going to write an assertion here. But if it's not the fault of the caller or your method's execution in the context of that call, then just throw an exception...you could end up throwing an AssertionError to a caller that could easily have handled the exception and gone on executing.
IMHO, the time to use assertions is to nail down the caller and your own method. That means, as long as you've listed the precondition of a method, you should be free to assert that precondition is true as soon as your method is entered. If the caller did not call your method properly by ensuring that the precondition is met, it is not unreasonable for your method to simply trundle along and let whatever problems that will happen, happen. After all, the caller did not live up to their responsibility. Much more helpful, though, is to perform the assertion that will specify the problem exactly, and since the behavior of your method is undefined if the precondition isn't met, this is a perfectly valid and helpful thing to do (above and beyond the call, even), as long as you've made the caller's responsibilities abundantly clear in the documentation.
This intersects the real world a bit harshly, though. You don't want AssertionErrors propagating to the top of your application if it's going to cause failure in a spectacular crash kind of way. Yet, having assertions enabled in production systems can sometimes nail down where exactly things are going wrong...I can't tell you the number of times I've worked on a complex system in which a NullPointerException is raised and it's not clear at all where that NPE originated (usually from a null record in the DB that was supposed to be set, at some time way earlier by a completely different system, to a non-null value...great, now you know what the problem is, but you still haven't a clue which bit of software is the one responsible for the bug!).
Most apps have a top-level handler for exceptions to catch them, log them explicitly, and continue functioning in whatever ways they can. I don't see any reason to do the same thing for assertions at an even higher level.
As long as a handler was built into the app with production scenarios in mind, I think it is equally valid to assert at the end of your method that your method does what you think it does.
There is the little matter now of performance--all of these checks no doubt will cause some apps to have bottlenecks in undesirable places. This is why I almost always write some kind of assertion class that performs the assertions for me along with some threshold int I pass in. That way, I can configure the Assertion class to skip all assertions below some threshold that I can dynamically configure in the runtime system. Furthermore, the Assertion class does nothing at all if I set an ASSERTION_DISABLE constant to true. In this way, I can compile out all that assertion code if I really want to max out performance, or I can leave it enabled and set the threshold to execute whatever assertions I want. I find that in 99% of the cases, there is little performance impact of leaving them on.
sev
[ February 27, 2004: Message edited by: sever oon ]