In the previous lesson we introduced exceptions.
Throwing exceptions
Instead of catching an exception and handling it in the current method, you could choose to throw it back to the client object. You would do this if different clients might need to handle the situation in different ways. If you throw an exception you need to decide whether to throw a checked or an unchecked exception:
Throw a checked exception for situations from which the client object or the user can recover from.
Throw an unchecked exception for programming errors.
If you look at the Animal class, it currently includes the following method to update the animal's age:
The method ought to validate the argument value to prevent nonsensical age values from being set, such as a negative or large number. Because the programmer can prevent an invalid value from being passed to the method it would be appropriate to throw an unchecked exception, and the Java supplied IllegalArgumentException is ready made for this purpose:
- All exceptions allow you to pass a
Stringwhich can be used to provide helpful information to the client object. In the case of unchecked exceptions, as above, this is useful when debugging the program
You can see the exception being thrown if you use the following sample code:
It is also possible for constructors to throw an exception, and noticing that the animal's age is set in the constructor you first might be tempted to invoke the setAge() method rather than directly assign the argument value, as follows:
You will notice, however, that NetBeans indicates a warning glyph on the setAge() statement which if you hover over warns you that you are invoking an overridable method from within a constructor. The reason for this warning is that should any subclass of Animal override the setAge() method it is possible that there will be uninitialised instance variables. To illustrate this, suppose you define a class called Dog where you want the age to be set in "human years" as defined by a multiplier:
- The
Dogclass introduces a new instance variable calledageMultiplier, which is specified as an additional argument inside the constructor, and assigned within it - The
setAge()method is overridden to output the given age by the multiplier
Try the following code:
Your intention would be that the output would be 14 (the result of multiplying 2 by 7) but in fact you will receive zero. This is because the superclass constructor of Dog, being Animal, will be run before the Dog constructor, and therefore the ageMultiplier instance variable will not be initialised in time.
The Dog class will not form part of the application in this course and may be deleted from the project if you wish.
Given that the setAge() method now performs validation on the age argument, and you have seen that it is inappropriate to invoke an overridable method from the constructor, your next thought might be to duplicate the age validation code inside the constructor. But code duplication is to be avoided wherever possible, so a better approach would be to define a private helper method to perform it:
Now you can modify the setAge() method to invoke the helper method:
Likewise, you can invoke the helper method from the constructor, too:
Methods defined as private cannot be overridden, so the earlier problem we saw with setAge() cannot occur.
In the next lesson you will learn how to create your own exception class.