import java.io.File; import java.io.FileNotFoundException; import java.util.Scanner; /* EmployeesGrossPay3.java ** Java application that reports the gross pay for each employee for which ** data is present in a specified data file. Its main purpose is to illustrate ** how to use a Scanner object for doing "file processing", as discussed in ** Chapter 6 of Reges & Stepp's textbook. ** ** This application differs from its predecessor (having same name, but ending ** in '2' rather than '3') in that this one is designed for a data file with a ** slightly different format. Specifically, the sequence of "hours worked" ** values within each employee record ends with a sentinel value of -1. ** In effect, occurrences of this sentinel act as record terminators. In ** the previous version of this application, the newline character fulfilled ** that role (i.e., the end of a line marked the end of a record). ** ** The name of the data file is provided via a command line argument (what ** jGrasp calls a "run argument"), but if no such argument is provided, a ** default name is used. ** ** The data file is assumed to be such that each employee record contains ** ** --an employee ID (an integer, but not representing any quantity, so we ** treat it as a String), ** --a name (necessarily a single token, meaning that no whitespace may ** appear in it), ** --an hourly wage (real number), ** --a sequence of hours-worked values (real numbers), one for each work ** period, followed by -1, which acts as a "sentinel" value marking ** the end of a record. ** ** Here is a sample data file to illustrate (where the column headings are ** not part of the file): ** ** ID Name wage hours worked ** +----------------------------------------------+ ** |6435 Smith 21.50 8.4 7.4 9.7 4.7 10.9 -1 | ** |0375 Jones 16.0 8.0 7.5 8.5 2.5 9.3 8.1 -1 | ** |4986 Thomas 15.75 8.4 4.6 10.3 -1 | ** +----------------------------------------------+ ** ** The above is a nicely formatted data file, in which each employee record ** occupies one line, but the fact that -1's are used as record terminators ** means that an employee record can be split over multiple lines and that ** multiple employee records (or portions thereof) can occupy the same line. ** For example, the following file contains the same data as above and, when ** processed by the application, should yield the same results. ** ** +----------------------------------------+ ** |6435 Smith 21.50 8.4 7.4 | ** |9.7 4.7 10.9 -1 0375 Jones 16.0 8.0 | ** | 7.5 8.5 2.5 9.3 8.1 -1 4986 Thomas | ** |15.75 8.4 4.6 | ** |10.3 | ** +----------------------------------------+ */ public class EmployeesGrossPay3 { private static final double HOURS_WORKED_SENTINEL = -1.0; /* Note: It is necessary to include the "throws" clause in the method heading ** because FileNotFoundException is a "checked" exception. */ public static void main(String[] args) throws FileNotFoundException { // Establish the name of the input file. String DEFAULT_FILE_NAME = "employees3.txt"; String fileName; if (args.length != 0) // name of input file is args[0] (the run argument) { fileName = args[0]; } else { fileName = DEFAULT_FILE_NAME; } // Create a Scanner object that can read from the input file. Scanner input = new Scanner(new File(fileName)); // Process the records in the input file. while (input.hasNext()) { processEmployee(input); } System.out.println("\nProgram terminating."); } /* Computes and reports the gross pay of a single employee. ** In doing so, it consumes one employee record (reading through ** the sentinel value marking the end of the record). */ private static void processEmployee(Scanner in) { in.next(); // read employee ID, but ignore it String emplName = in.next(); // Read and save employee name double hourlyWage = in.nextDouble(); // Read and save employee hourly wage // Now read through the hours worked values in the employee record // and sum them to compute the total number of hours worked. double totHoursWorked = 0; // to accumulate hours worked values double hoursWorked = in.nextDouble(); while (hoursWorked != HOURS_WORKED_SENTINEL) { totHoursWorked = totHoursWorked + hoursWorked; hoursWorked = in.nextDouble(); } // Having computed total hours worked, compute the employee's gross pay. double grossPay = grossPay(hourlyWage, totHoursWorked); // Print the employee's name and gross pay. System.out.printf("%s: %7.2f\n", emplName, grossPay); } /* Given an employee's hours worked and hourly wage, returns the ** corresponding gross pay. */ private static double grossPay(double hours, double wage) { final double OT_HOURS_THRESHOLD = 40.0; final double OT_WAGE_RATIO = 1.5; double regularHours, overtimeHours; if (hours > OT_HOURS_THRESHOLD) { regularHours = OT_HOURS_THRESHOLD; overtimeHours = hours - OT_HOURS_THRESHOLD; } else { regularHours = hours; overtimeHours = 0; } return (regularHours + (OT_WAGE_RATIO * overtimeHours)) * wage; } }