What's all the fuss about java assertions?

I want to take the OCMJD exam and I am reading the book "SCJD Exam with J2SE 5" written by Andrew Monkhouse and Terry Camerlengo.

At page 49 it says:

Caution You should never use assertions to validate the inputs on public methods—these are methods that other programmers may use, and they may not honor your requirements. You should validate these inputs regardless of whether or not assertions are turned on at runtime.

And it even gives an example of correct use of assertions:

In my opinion this code has a big problem: if you withdraw something from your account and the balance becomes less than 0, then no exceptional event is signaled if assertions are turned off (for example in a production environment).
So from my point of view, I should validate these post-conditions and throw a checked exception instead of doing that assertion thing.

K. Tsang wrote:Looking at Andrew's assertion example, it has a problem. The assert statement is checked after it has deducted the withdrawal amount. Instead a better version may look something like

I don't want to be harsh, but you are completely wrong here! That's exactly what the caution (mentioned in the OP) is all about: don't use assertions to verify parameters (arguments) of a public method. So his example is spot on!

Checking the balance after makes sense if it's not possible for the balance to be negative. For example, reduceBalance checks the balance itself and throws an exception if there are insufficient funds. This way the program doesn't rely on assertions for correct behavior. They are only used for documentation or testing.

Assertions aren't normally used on parameters because the method can not make any guarantees of what values they have.

Alexandru Dragoi
Ranch Hand

Joined: May 09, 2008
Posts: 33

posted Jul 27, 2013 04:45:20

0

Sresh Rangi wrote:Checking the balance after makes sense if it's not possible for the balance to be negative. For example, reduceBalance checks the balance itself and throws an exception if there are insufficient funds. This way the program doesn't rely on assertions for correct behavior. They are only used for documentation or testing.

Assertions aren't normally used on parameters because the method can not make any guarantees of what values they have.

That's more realistic!
I was confused because the implementation for reduceBalance was not revealed so I thought that the assertion was the only check to be done.
If the reduceBalance method checks and validates the withdrawalAmount against the current balance by throwing an exception, then I think that this is a good implementation.

However, I would prefer a checked exception (instead of a runtime IllegalArgumentException/IllegalStateException) to be thrown if the validation fails. That is because if the user tries to withdraw an invalid amount, this should be a recoverable condition and not a programming error.

Alexandru Dragoi wrote:However, I would prefer a checked exception (instead of a runtime IllegalArgumentException/IllegalStateException) to be thrown if the validation fails. That is because if the user tries to withdraw an invalid amount, this should be a recoverable condition and not a programming error.

Throwing a checked exception when this validation fails is of course even better. But you always have to be careful when using checked exceptions: when used thoughtless they can clutter your code in no time, certainly when you are designing/creating a framework/library/API. And as already mentioned in my previous post: I used IllegalArgumentException/IllegalStateException to guarantee correct use of the API as possible. So that's to prevent a developer of abusing the API, when it goes wrong it's not a recoverable condition, the developer just mad a mistake. The exception which is thrown when a room/contractor is already booked, is definitely a checked exception.

Alexandru Dragoi
Ranch Hand

Joined: May 09, 2008
Posts: 33

posted Jul 28, 2013 05:50:50

0

Roel De Nijs wrote:

Alexandru Dragoi wrote:However, I would prefer a checked exception (instead of a runtime IllegalArgumentException/IllegalStateException) to be thrown if the validation fails. That is because if the user tries to withdraw an invalid amount, this should be a recoverable condition and not a programming error.

Throwing a checked exception when this validation fails is of course even better. But you always have to be careful when using checked exceptions: when used thoughtless they can clutter your code in no time, certainly when you are designing/creating a framework/library/API. And as already mentioned in my previous post: I used IllegalArgumentException/IllegalStateException to guarantee correct use of the API as possible. So that's to prevent a developer of abusing the API, when it goes wrong it's not a recoverable condition, the developer just mad a mistake. The exception which is thrown when a room/contractor is already booked, is definitely a checked exception.

Let me see if I understand well...

So in my case for a reduceBalance(int withdrawalAmount) method, if I choose to do this:

I must specify in the javadoc that it is a violation to withdraw an something that is bigger than the current amount.
So it will be up to the client of the API who calls this method to perform the actual validation.

Because I specify this in the javadoc, if the client that implements the API fails to adhere to the contract, then this is a programming error and the runtime exception is suitable for my case.

Alexandru Dragoi wrote:So it will be up to the client of the API who calls this method to perform the actual validation.

Exactly But this client could be some kind of service (it doesn't has to be a client like some user interface).

Imagine a BankAccount class whiich has an instance variable balance and a method withdraw. The amount to withdraw can never be bigger than the balance total. This domain class will only be used in service classes, not directly by any GUI. So to validate this rule (and to protect your API) you implement the method like this:

The BankAccountService has also a method to withdraw an amount of a certain balance. Because this service will be used by (several) GUI(s) you'll throw a checked exception here, because this is a recoverable situation (user must choose a lower amount to withdraw). An implementation could be:

And as an illustration of an API/library where wrong usage of checked exceptions can result in cluttered code, have a look at this JSONObject class. If you have a look at the several put-methods you'll see this method throws a checked JSONException when the key is null. That means I always have to catch (or handle) this exception even if I know for sure that the key can never be null, like in this example:

So it requires 3-4 lines of extra code for a situation which can never occur! Another drawback: you can never test the catch-clause because it will never occur. So if you use a quality management platform (e.g. SonarQube) to measure your source code quality (and test coverage) you can never get a 100% score for this class, because of this checked exception.

Checked exceptions are nice and a very powerful language structure, but they must be used with great care; otherwise it will be a burden instead of a blessing!

Alexandru Dragoi
Ranch Hand

Joined: May 09, 2008
Posts: 33

posted Jul 28, 2013 07:57:29

0

Thanks Roel, I think I get the idea!
Indeed, for the BankAccount which cannot be directly called by the API users (may well be package-private), the IllegalArgumentException seems more suitable than a checked exception.
On the other hand, the BankAccountService makes part of the public API and it is better to throw a checked exception here, because the API users must have a way to respond.

Now regarding JSONObject, it looks horrible! And they cannot even change the API without breaking their clients code.
JSONObject seems to be doomed forever!

Alexandru Dragoi wrote:Now regarding JSONObject, it looks horrible! And they cannot even change the API without breaking their clients code.
JSONObject seems to be doomed forever!

It's not completely doomed: they can simply make JSONException a runtime exception instead of a checked one. That shouldn't break any client code.

In my current project I have to use this class. So I know what it means for your code if you have to use a badly designed API But I created a JSONUtils class with a few utility methods to gracefully handle this issue: e.g. the method put(JSONObject jsonObject, String key, Object value) checks if the key is null and if it's null a runtime exception is thrown (because it means 1 of the developers has made a mistake during development). So only in this utility class the JSONException can appear, but nowhere else. So this "workaround" decreases code cluttering and allows us to achieve 100% test coverage. That's how it should be designed in the 1st place.

Alexandru Dragoi
Ranch Hand

Joined: May 09, 2008
Posts: 33

posted Jul 29, 2013 06:48:20

0

Thanks for this discussion Roel!
That was more than enough for me to understand well what I needed to understand!

I’ve looked at a lot of different solutions, and in my humble opinion Aspose is the way to go. Here’s the link: http://aspose.com