This week's book giveaway is in the OCAJP 8 forum. We're giving away four copies of OCA Java SE 8 Programmer I Study Guide and have Edward Finegan & Robert Liguori on-line! See this thread for details.
Hi, In the K&B book (p.264) the following rule for assertions and private methods is given: "Do use assertions to validate arguments to a private method."
This rule comes after the one saying don't use assertions to validate arguments to *public* methods, basically because you can't be guaranteed that assertions will be enabled in a deployed application.
Now, why doesn't this same rationale against using assertions to validate in a public method hold for private methods? For private methods, they give the reason that "you almost certainly wrote (or control) any code that calls it", and so, presumably, you can know or control whether assertions are enabled. But I guess I don't see this; can't a public class with public methods also have private methods that perhaps perform some utility work? And in such a class you might not have any more control over whether assertions are enabled/disabled than in a class w/ purely public methods.
In short, I don't see their rationale for allowing assertions to validate arguments to a private method either. But, it's likely I'm missing something in their account (or perhaps there is another rationale that they don't give that would clear this up). Any thoughts?
There are also a few situations where you should not use them:
* Do not use assertions for argument checking in public methods.
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.
Thanks for the response. I will look at that page. I wasn't questioning the proviso against assertions in public methods, just wondering about the rationale for their use in private methods. Anyway, I'll see what this doc says.
I think the rationale for using assertions in a private method is not whether or not assertions are enabled but that you control what gets passed to the private method.
As Barry said, your public method has to check its parameters regardless of whether assertions are turned on or off, because you can't control what is going to be passed in as an argument. (I've learned to assume there will always be at least one lunatic using any public interface I write.)
But you can control what gets passed to your private method (because you wrote the class). So if your private method is a utility method called by one of your public methods, you can be certain that only correct values are passed as arguments to the private method.
Using an assertion inside the private method is safe because presumably, you will have tested your code before anybody else uses it, so if assertions are turned on and an AssertionError occurs, it will be due to SomethingMajorJustHappened and not because of a programming error.
Assertions are used to promote the 'fail early' concept. In fact, this concept is fundamental to software design, but it is widely misunderstood. The rule is simple; "fail early and fail as early as possible". The most optimal point to fail is at build/compile time. That is why we have generics, automated progressive testing (plug: JTiger) and the like. However, there are certain situations that are dynamically created - that is, they are unpredictable until runtime. The point being, as soon as they are detected at runtime, you should fail immediately - the assert keyword provides one ability to do this.
You should not, however, use the assert keyword to validate your client contracts (public APIs), since it is you (the developer) that is trying to fail yourself - you want to fail in a different way if your software is behaving correctly, but a client is not meeting your contract. For example, you might provide a callback method implementation that accepts a reference type argument; if it is null, you cannot use it - in this case, you would fail with a NullPointerException as early as possible (check the argument immediately upon entry into the method).
Another case is that you might accept an int, but only within the range 0-100, so if a value outside of these bounds is sent to your public method, you fail with an IllegalArgumentException. However, in this case, you really should be using an enumeration (type-safe or 1.5) with the 100 values explicitly specified. That way, you get compile-time failure if you send the wrong value (since it is type-safe) instead of early runtime failure; and the fundamental rule says that this is better, and better is good, right?
As a side note, I'm all for introducing a keyword that acts as a modifier on reference declarations that can never be null, and if it can be determined at compile-time that the reference may refer to null, fail compilation, and if that reference ever becomes null at runtime, fail immediately (I wonder if there is an RFE for that?).
For private methods where you are your own client, you might want to use assertions for early failure. Personally, I find no good use for them, but then, I'm a purist and I strive for perfection (and assertions violate perfection in very pedantic detail). I would fail immediately, but using other more appropriate mechanisms (I'm avoiding the debate for a reason). There are times, however, where I explicitly throw an AssertionError. A perfect example is the newcomer mistake of ignoring an exception. First, one must concede that Java exception handling in the core API is somewhat broken. Let's pick on an obvious example; Thread.sleep may throw a checked exception, but there are times when you (the developer) don't care, right? Is that reasonable grounds to ignore the exception? NO! Instead, fail in the handler disastrously (e.g. AssertionError). That way, you get better regression (if in the future you inadvertantly make changes such that the error/exception is thrown, you have early failure and you find out immediately), and it's also more explicit to readers of your code (including yourself) what the intention is.
Anyway, enough ranting from me. [ May 12, 2005: Message edited by: Tony Morris ]