Payroll-Exceptions02 - Exercise

Contact Us or call 1-877-932-8228
Payroll-Exceptions02 - Exercise

Payroll-Exceptions02

Duration: 20 to 30 minutes.

Our payroll program can now handle things like a bad numeric input for pay rate (valid format, but not sensible, like a negative number) in a more comprehensive manner. We already are checking the numeric inputs from the keyboard, but there is no guarantee that later code will remember to do this. Using an exception mechanism guarantees protection from invalid values.

  1. In the util package, create an exception class for InvalidValueException. Note that the Java API already contains a class for this purpose, IllegalArgumentException, but it is a RuntimeException - we would like ours to be a checked exception.
  2. In Employee (and potentially its subclasses), change the constructors that accept pay rate and the setPayRate methods to now throw that exception (a question to ask yourself - is it necessary to actually test the pay rate value anywhere other than in the Employee class setPayRate method?). You will see that the effect of throwing the exception ripples through a lot of code.
  3. For any code that calls those constructors/methods, choose an appropriate approach to dealing with the potential exception.
  4. The solution uses the validators from the previous challenge exercise, it will work without that feature, but feel free to add that logic into your code as well.

Solution:

Solutions/Payroll-Exceptions02/util/InvalidValueException.java
package util;
public class InvalidValueException extends Exception {

  public InvalidValueException() { super(); }
  public InvalidValueException(String message) { super(message); }
  public InvalidValueException(Throwable cause) { super(cause); }
  public InvalidValueException(String message, Throwable cause) {
    super(message, cause);
  }

}

Solution:

Solutions/Payroll-Exceptions02/employees/Employee.java
package employees;
import finance.Payable;
import util.*;

public class Employee extends Person implements Payable {

---- C O D E   O M I T T E D ----
  public Employee(String firstName, String lastName, double payRate) 
				throws InvalidValueException {
    super(firstName, lastName);
    setPayRate(payRate);
  }
  public Employee(String firstName, String lastName,
		int dept, double payRate)
				throws InvalidValueException {
    this(firstName, lastName, dept);
    setPayRate(payRate);
  }

---- C O D E   O M I T T E D ----
  public void setPayRate(double payRate) throws InvalidValueException {
    DoubleValidator val = new ValidatePayRate();
    if (!val.accept(payRate))
      throw new InvalidValueException(payRate + " is an invalid pay rate");
    this.payRate = payRate;
  }


---- C O D E   O M I T T E D ----
}

The marking of setPayRate throws InvalidValueException ripples through the constructors, so they should be marked as well.

Solution:

Solutions/Payroll-Exceptions02/employees/ExemptEmployee.java
package employees;

import util.*;

public class ExemptEmployee extends Employee {
  
  public ExemptEmployee() {
  }
  public ExemptEmployee(String firstName, String lastName) {
    super(firstName, lastName);
  }
  public ExemptEmployee(String firstName,String lastName, int dept) {
    super(firstName, lastName, dept);
  }
  public ExemptEmployee(String firstName, String lastName, double payRate)
				throws InvalidValueException {
    super(firstName, lastName, payRate);
  }
  public ExemptEmployee(String firstName, String lastName, 
  			int dept, double payRate)
				throws InvalidValueException {
    super(firstName, lastName, dept, payRate);
  }  
  public String getPayInfo() {
    return "Exempt Employee " + getId() + " dept " + getDept() + 
           " " + getFirstName() + " " + getLastName() + 
           " paid " + getPayRate();
  }
}

Calling super-constructors that throw our exception requires that these constructors also be marked. The other classes, not shown, should be similarly marked.

Solution:

Solutions/Payroll-Exceptions02/Payroll.java
import employees.*;
import vendors.*;
import util.*;
import finance.*;

public class Payroll {	
	public static void main(String[] args) {

---- C O D E   O M I T T E D ----

		for (int i = 0; i < e.length; i++) {
			try {

---- C O D E   O M I T T E D ----

				do {
					payRate = KeyboardReader.getPromptedDouble("Enter pay rate: ", 
									"Pay rate must be numeric");
					if (payRate < 0.0) System.out.println("Pay rate must be >= 0");
				} while (payRate < 0.0);
	
				switch (type) {
					case 'e':
					case 'E': e[i] = new ExemptEmployee(fName, lName, dept, payRate);
										break;
					case 'n':
					case 'N': do {
											hours = KeyboardReader.getPromptedDouble(
														"Enter hours: ", "Hours must be numeric");
											if (hours < 0.0) 
												System.out.println("Hours must be >= 0");
										} while (hours < 0.0);
										e[i] = new NonexemptEmployee(fName, lName, dept, 
													payRate, hours);
										break;
					case 'c':
					case 'C': do {
											hours = KeyboardReader.getPromptedDouble(
														"Enter hours: ", "Hours must be numeric");
											if (hours < 0.0) 
												System.out.println("Hours must be >= 0");
										} while (hours < 0.0);
										e[i] = new ContractEmployee(fName, lName, dept, 
													payRate, hours);
				}

---- C O D E   O M I T T E D ----

			} catch (InvalidValueException ex) {
					System.out.println(ex.getMessage());
					i--;	//failed, so back up counter to repeat this employee
				}
		}

---- C O D E   O M I T T E D ----

	}
}

Since we are already checking the values of the pay rate and hours, we shouldn't expect to see any exceptions thrown, so it is reasonable to put the entire block that gets the employee data and creates an employee in a try block. If we decrement the counter upon a failure, then that employee's data will be requested again.

You might want to test your logic by temporarily changing one of the test conditions you use when reading input (like hours > 0 to hours > -20), so that you can the result (keep count of how many employees you are asked to enter).

Next