Java programming course: 7.2 Throwing exceptions

 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:

public void setAge(int age) {
    this.age = 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:

// Change the animal's age
public void setAge(int age) {
    // Ensure new age is between 0 and 50
    if ((age >= 0) && (age <= 50)) {
        this.age = age;
    } else {
        throw new IllegalArgumentException("Age must be 0 - 50");
    }
}
 
  • All exceptions allow you to pass a String which 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:

Animal leo = new Lion("Leo", Gender.MALE, 5);
leo.setAge(-12);
 

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:

public Animal(String name, Gender gender, int age) {
    this.name = name;
    this.gender = gender;
    setAge(age); // DON'T DO THIS
    dateAdmitted = new Date(); // today's date is assumed

    // Add this animal's age to the combined age total
    combinedAge += this.age;
}
 

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:

package virtualzoo.core;

public class Dog extends Animal {
    
    private int ageMultiplier;

    public Dog(String myName, Gender myGender, int myAge,
							int ageMultiplier) {
        super(myName, myGender, myAge);
        this.ageMultiplier = ageMultiplier;
    }

    @Override
    public boolean isEndangered() {
        return true;
    }

    @Override
    public String favouriteFood() {
        return "bone";
    }

    @Override
    public void setAge(int age) {
        super.setAge(age);
        System.out.println("In human years = " +
                             (age * ageMultiplier));
    }
    
}
 
  • The Dog class introduces a new instance variable called ageMultiplier, 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:

Animal fido = new Dog("Fido", Gender.MALE, 2, 7);
System.out.println(fido.getAge());
 

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:

private void validateAge(int age) {
    // Ensure new age is between 0 and 50
    if ((age < 0) || (age > 50)) {
        throw new IllegalArgumentException("Age must be 0 - 50");
    }
}
 

Now you can modify the setAge() method to invoke the helper method:

public void setAge(int age) {
    validateAge(age);
    this.age = age;
}
 

Likewise, you can invoke the helper method from the constructor, too:

public Animal(String name, Gender gender, int age) {
    validateAge(age);
        
    this.name = name;
    this.gender = gender;
    this.age = age;
    dateAdmitted = new Date(); // today's date is assumed

    // Add this animal's age to the combined age total
    combinedAge += this.age;
}
 

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.

Next lesson: 7.3 Creating your own exception class


Print
×
Stay Informed

When you subscribe, we will send you an e-mail whenever there are new updates on the site.

Related Posts

 

Comments

No comments made yet. Be the first to submit a comment
Monday, 27 October 2025

Captcha Image