Chapter 8

Saving Time and Money: Reusing Existing Code

In This Chapter

arrow Adding new life to old code

arrow Tweaking your code

arrow Making changes without spending a fortune

Once upon a time, there was a beautiful princess. When the princess turned 25 (the optimal age for strength, good looks, and fine moral character), her kind father brought her a gift in a lovely golden box. Anxious to know what was in the box, the princess ripped off the golden wrapping paper.

When the box was finally opened, the princess was thrilled. To her surprise, her father had given her what she had always wanted — a computer program that always ran correctly. The program did everything the princess wanted and did it all exactly the way she wanted it to be done. The princess was happy, and so was her kind, old father.

As time went on, the computer program never failed. For years on end, the princess changed her needs, expected more out of life, made increasing demands, expanded her career, reached for more and more fulfillment, juggled the desires of her husband and her kids, stretched the budget, and sought peace within her soul. Through all this, the program remained her steady, faithful companion.

As the princess grew old, the program became old along with her. One evening, as she sat by the fireside, she posed a daunting question to the program. “How do you do it?” she asked. “How do you manage to keep giving the right answers, time after time, year after year?”

“Clean living,” replied the program. “I swim 20 apps each day, I take C++ to Word off viruses, I avoid hogarithmic algorithms, I link Java in moderation, I say GNU to bugs, I don’t smoke to backup, and I never byte off more than I can queue.”

Needless to say, the princess was stunned.

Defining a Class (What It Means to Be an Employee)

Wouldn’t it be nice if every piece of software did just what you wanted it to do? In an ideal world, you could just buy a program, make it work right away, plug it seamlessly into new situations, and update it easily whenever your needs change. Unfortunately, software of this kind doesn’t exist. (Nothing of this kind exists.) The truth is that no matter what you want to do, you can find software that does some of it, but not all of it.

This is one of the reasons why object-oriented programming has been so successful. For years, companies were buying prewritten code only to discover that the code didn’t do what they wanted it to do. So what did the companies do about it? They started messing with the code. Their programmers dug deep into the program files, changed variable names, moved subprograms around, reworked formulas, and generally made the code worse. The reality was that if a program didn’t already do what you wanted it to do (even if it did something ever so close to what you wanted), you could never improve the situation by mucking around inside the code. The best option was always to chuck the whole program (expensive as that was) and start all over again. What a sad state of affairs!

With object-oriented programming, a big change has come about. At its heart, an object-oriented program is made to be modified. With correctly written software, you can take advantage of features that are already built-in, add new features of your own, and override features that don’t suit your needs. And the best part is that the changes you make are clean. No clawing and digging into other people’s brittle program code. Instead, you make nice, orderly additions and modifications without touching the existing code’s internal logic. It’s the ideal solution.

The last word on employees

When you write an object-oriented program, you start by thinking about the data. You’re writing about accounts. So what’s an account? You’re writing code to handle button clicks. So what’s a button? You’re writing a program to send payroll checks to employees. What’s an employee?

In this chapter’s first example, an employee is someone with a name and a job title. Sure, employees have other characteristics, but for now I stick to the basics. The code in Listing 8-1 defines what it means to be an employee.

Listing 8-1: What Is an Employee?

  import static java.lang.System.out;

public class Employee {
   private String name;
   private String jobTitle;

   public void setName(String nameIn) {
      name = nameIn;
   }

   public String getName() {
      return name;
   }

   public void setJobTitle(String jobTitleIn) {
      jobTitle = jobTitleIn;
   }

   public String getJobTitle() {
      return jobTitle;
   }

   public void cutCheck(double amountPaid) {
      out.printf("Pay to the order of %s ", name);
      out.printf("(%s) ***$", jobTitle);
      out.printf("%,.2f ", amountPaid);
   }
}

According to Listing 8-1, each employee has seven features. Two of these features are fairly simple. Each employee has a name and a job title. (In Listing 8-1, the Employee class has a name field and a jobTitle field.)

And what else does an employee have? Each employee has four methods to handle the values of the employee’s name and job title. These methods are setName, getName, setJobTitle, and getJobTitle. I explain methods like these (accessor methods) in Chapter 7.

On top of all that, each employee has a cutCheck method. The idea is that the method that writes payroll checks has to belong to one class or another. Because most of the information in the payroll check is customized for a particular employee, you may as well put the cutCheck method inside the Employee class.

For details about the printf calls in the cutCheck method, see the section entitled “Cutting a check,” later in this chapter.

Putting your class to good use

The Employee class in Listing 8-1 has no main method, so there’s no starting point for executing code. To fix this deficiency, the programmer writes a separate program with a main method and uses that program to create Employee instances. Listing 8-2 shows a class with a main method — one that puts the code in Listing 8-1 to the test.

Listing 8-2: Writing Payroll Checks

  import java.util.Scanner;
import java.io.File;
import java.io.IOException;

public class DoPayroll {

   public static void main(String args[])
                          throws IOException {
      Scanner diskScanner =
         new Scanner(new File("EmployeeInfo.txt"));

      for (int empNum = 1; empNum <= 3; empNum++) {
         payOneEmployee(diskScanner);
      }

      diskScanner.close();
   }

   static void payOneEmployee(Scanner aScanner) {
      Employee anEmployee = new Employee();

      anEmployee.setName(aScanner.nextLine());
      anEmployee.setJobTitle(aScanner.nextLine());
      anEmployee.cutCheck(aScanner.nextDouble());
      aScanner.nextLine();
   }
}

ontheweb_fmt.eps To run the code in Listing 8-2, your hard drive must contain a file named EmployeeInfo.txt. Fortunately, the stuff that you download from this book's website (www.allmycode.com/JavaForDummies) comes with an EmployeeInfo.txt file. You can import the downloaded material into any of the three most popular Java IDEs (Eclipse, NetBeans, and IntelliJ IDEA). If you import into Eclipse, you get a project named 08-02. That project typically lives on your hard drive in a folder named c:Usersyour-user-nameworkspace8-02. Directly inside that folder, you have a file named EmployeeInfo.txt.

cross-reference.eps For more words of wisdom about files on your hard drive, see the “Working with Disk Files (A Brief Detour)” section in this chapter.

The DoPayroll class in Listing 8-2 has two methods. One of the methods, main, calls the other method, payOneEmployee, three times. Each time around, the payOneEmployee method gets stuff from the EmployeeInfo.txt file and feeds this stuff to the Employee class’s methods.

Here’s how the variable name anEmployee is reused and recycled:

  • The first time that payOneEmployee is called, the statement anEmployee = new Employee() makes anEmployee refer to a new object.
  • The second time that payOneEmployee is called, the computer executes the same statement again. This second execution creates a new incarnation of the anEmployee variable that refers to a brand-new object.
  • The third time around, all the same stuff happens again. A new anEmployee variable ends up referring to a third object.

The whole story is pictured in Figure 8-1.

9781118407806-fg0801.tif

Figure 8-1: Three calls to the payOne Employee method.

Cutting a check

Listing 8-1 has three printf calls. Each printf call has a format string (like "(%s) ***$") and a variable (like jobTitle). Each format string has a placeholder (like %s) that determines where and how the variable’s value is displayed.

For example, in the second printf call, the format string has a %s placeholder. This %s holds a place for the jobTitle variable’s value. According to Java’s rules, the notation %s always holds a place for a string and, sure enough, the variable jobTitle is declared to be of type String in Listing 8-1. Parentheses and some other characters surround the %s placeholder, so parentheses surround each job title in the program’s output. (See Figure 8-2.)

9781118407806-fg0802.tif

Figure 8-2: Everybody gets paid.

Back in Listing 8-1, notice the comma inside the %,.2f placeholder. The comma tells the program to use grouping separators. That’s why, in Figure 8-2, you see $5,000.00, $7,000.00, and $10,000.00 instead of $5000.00, $7000.00, and $10000.00.

tip.eps Grouping separators vary from one country to another. For instance, in France, to write the number one thousand (mille), you write 1 000,00. Java can Frenchify your number automatically with a statement like out.print(new java.util.Formatter().format(java.util.Locale.FRANCE, "%,.2f", 1000.00)). For details, see the API (Application Programming Interface) documentation for Java’s Formatter and Locale classes.

Working with Disk Files (A Brief Detour)

In previous chapters, programs read characters from the computer’s keyboard. But the code in Listing 8-2 reads characters from a specific file. The file (named EmployeeInfo.txt) lives on your computer’s hard drive.

This EmployeeInfo.txt file is like a word processing document. The file can contain letters, digits, and other characters. But unlike a word processing document, the EmployeeInfo.txt file contains no formatting — no italics, no bold, no font sizes, nothing of that kind.

The EmployeeInfo.txt file contains only ordinary characters — the kinds of keystrokes that you type while you play a guessing game from Chapters 5 or 6. Of course, getting guesses from a user’s keyboard and reading employee data from a disk file aren’t exactly the same. In a guessing game, the program displays prompts, such as Enter an int from 1 to 10. The game program conducts a back-and-forth dialogue with the person sitting at the keyboard. In contrast, Listing 8-2 has no dialogue. This DoPayroll program reads characters from a hard drive and doesn’t prompt or interact with anyone.

Most of this chapter is about code reuse. But Listing 8-2 stumbles upon an important idea — an idea that’s not directly related to code reuse. Unlike the examples in previous chapters, Listing 8-2 reads data from a stored disk file. So in the following sections, I take a short side trip to explore disk files.

Storing data in a file

The code in Listing 8-2 doesn’t run unless you have some employee data sitting in a file. Listing 8-2 says that this file is EmployeeInfo.txt. So before running the code of Listing 8-2, I created a small EmployeeInfo.txt file. The file is shown in Figure 8-3; refer to Figure 8-2 for the resulting output.

9781118407806-fg0803.tif

Figure 8-3: An Employee Info.txt file.

When you visit this book's web site (www.allmycode.com/JavaForDummies) and you download the book's code listings, you get a copy of the EmployeeInfo.txt file.

warning.eps To keep Listing 8-2 simple I insist that, when you type the characters in Figure 8-3, you finish up by typing 10000.00 and then pressing Enter. (Look again at Figure 8-3 and notice how the cursor is at the start of a brand-new line.) If you forget to finish by pressing Enter, then the code in Listing 8-2 will crash when you try to run it.

warning.eps Grouping separators vary from one country to another. The file shown in Figure 8-3 works on a computer configured in the United States where 5000.00 means “five thousand.” But the file doesn't work on a computer that's configured in what I call a “comma country” — a country where 5000,00 means “five thousand.” If you live in a comma country, and you use the file exactly as it's shown in Figure 8-3, you probably get an error message (an InputMismatchException) when you try to run this section's example. If so, change the number amounts in your file to match your country's number format. When you do, you should be okay.

This book’s website (www.allmycode.com/JavaForDummies) has tips for readers who need to create data files. This includes instructions for Windows, Linux, and Macintosh environments.

Copying and pasting code

In almost any computer programming language, reading data from a file can be tricky. You add extra lines of code to tell the computer what to do. Sometimes you can copy and paste these lines from other peoples’ code. For example, you can follow the pattern in Listing 8-2:

 /*
* The pattern in Listing 8-2
*/
import java.util.Scanner;
import java.io.File;
import java.io.IOException;

class SomeClassName {

   public static void main(String args[])
                          throws IOException {
      Scanner scannerName =
         new Scanner(new File("SomeFileName"));

      //Some code goes here

      scannerName.nextInt();
      scannerName.nextDouble();
      scannerName.next();
      scannerName.nextLine();

      //Some code goes here

      scannerName.close();
   }
}

You want to read data from a file. You start by imagining that you’re reading from the keyboard. Put the usual Scanner and next codes into your program. Then add some extra items from the Listing 8-2 pattern:

  • Add two new import declarations — one for java.io.File and another for java.io.IOException.
  • Type throws IOException in your method’s header.
  • Type new File(“ ”) in your call to new Scanner.
  • Take a file that’s already on your hard drive. Type that filename inside the quotation marks.
  • Take the word that you use for the name of your scanner. Reuse that word in calls to next, nextInt, nextDouble, and so on.
  • Take the word that you use for the name of your scanner. Reuse that word in a call to close.

Occasionally, copying and pasting code can get you into trouble. Maybe you’re writing a program that doesn’t fit the simple Listing 8-2 pattern. You need to tweak the pattern a bit. But to tweak the pattern, you need to understand some of the ideas behind the pattern.

That’s how the next section comes to your rescue. It covers some of these ideas.

Reading from a file

In previous chapters, programs read characters from the computer’s keyboard. These programs use things like Scanner, System.in, and nextDouble — things defined in Java’s API. The DoPayroll program in Listing 8-2 puts a new spin on this story. Instead of reading characters from the keyboard, the program reads characters from the EmployeeInfo.txt file. The file lives on your computer’s hard drive.

To read characters from a file, you use some of the same things that help you read characters from the keyboard. You use Scanner, nextDouble, and other goodies. But in addition to these goodies, you have a few extra hurdles to jump. Here’s a list:

  • You need a new File object. To be more precise, you need a new instance of the API’s File class. You get this new instance with code like

      new File("EmployeeInfo.txt")

    The stuff in quotation marks is the name of a file — a file on your computer’s hard drive. The file contains characters like those shown previously in Figure 8-3.

    At this point, the terminology makes mountains out of molehills. Sure, I use the phrases new File object and new File instance, but all you’re doing is making new File("EmployeeInfo.txt") stand for a file on your hard drive. After you shove new File("EmployeeInfo.txt") into new Scanner,

      Scanner diskScanner =
            new Scanner(new File("EmployeeInfo.txt"));

    you can forget all about the new File business. From that point on in the code, diskScanner stands for the EmployeeInfo.txt filename on your computer’s hard drive. (The name diskScanner stands for a file on your hard drive just as, in previous examples, the name keyboard stands for those buttons that you press day-in and day-out.)

    remember.eps Creating a new File object in Listing 8-2 is like creating a new Employee object later in the same listing. It’s also like creating a new Account object in the examples of Chapter 7. The only difference is that the Employee and Account classes are defined in this book’s examples. The File class is defined in Java’s API.

    warning.eps When you connect to a disk file with new Scanner, don’t forget the new File part. If you write new Scanner("EmployeeInfo.txt") without new File, the compiler won’t mind. (You won't get any warnings or error messages before you run the code.) But when you run the code, you won’t get anything like the results that you expect to get.

  • You must refer to the File class by its full name — java.io.File. You can do this with an import declaration like the one in Listing 8-2. Alternatively, you can clutter up your code with a statement like

      Scanner diskScanner =
    new Scanner(new java.io.File("EmployeeInfo.txt"));

  • You need a throws IOException clause. Lots of things can go wrong when your program connects to EmployeeInfo.txt. For one thing, your hard drive may not have a file named EmployeeInfo.txt. For another, the file EmployeeInfo.txt may be in the wrong directory. To brace for this kind of calamity, the Java programming language takes certain precautions. The language insists that when a disk file is involved, you acknowledge the possible dangers of calling new Scanner.

    You can acknowledge the hazards in several possible ways, but the simplest way is to use a throws clause. In Listing 8-2, the main method’s header ends with the words throws IOException. By adding these two words, you appease the Java compiler. It’s as if you’re saying “I know that calling new Scanner can lead to problems. You don’t have to remind me.” And, sure enough, adding throws IOException to your main method keeps the compiler from complaining. (Without this throws clause, you get an unreported exception error message.)

    cross-reference.eps For the full story on Java exceptions, read Chapter 13. In the meantime, add throws IOException to the header of any method that calls new Scanner(new File(. . ..

  • You must refer to the IOException class by its full name — java.io.IOException.

    You can do this with an import declaration like the one in Listing 8-2. Alternatively, you can enlarge the main method’s throws clause:

      public static void main(String args[])
                  throws java.io.IOException {

  • You must pass the file scanner’s name to the payOneEmployee method.

    In Listing 7-5 in Chapter 7, the getInterest method has a parameter named percentageRate. Whenever you call the getInterest method, you hand an extra, up-to-date piece of information to the method. (You hand a number — an interest rate — to the method. Figure 7-7 illustrates the idea.)

    The same thing happens in Listing 8-2. The payOneEmployee method has a parameter named aScanner. Whenever you call the payOneEmployee method, you hand an extra, up-to-date piece of information to the method. (You hand a scanner — a reference to a disk file — to the method.)

You may wonder why the payOneEmployee method needs a parameter. After all, in Listing 8-2, the payOneEmployee method always reads data from the same file. Why bother informing this method, each time you call it, that the disk file is still the EmployeeInfo.txt file?

Well, there are plenty of ways to shuffle the code in Listing 8-2. Some ways don’t involve a parameter. But the way that this example has arranged things, you have two separate methods — a main method and a payOneEmployee method. You create a scanner once inside the main method and then use the scanner three times — once inside each call to the payOneEmployee method.

Anything that you define inside a method is like a private joke that’s known only to the code inside that method. So, the diskScanner that you define inside the main method isn’t automatically known inside the payOneEmployee method. To make the payOneEmployee method aware of the disk file, you pass diskScanner from the main method to the payOneEmployee method.

cross-reference.eps To read more about things that you declare inside (and outside) of methods, see Chapter 10.

Who moved my file?

When you download the code from this book’s website, you’re going to find files named Employee.java and DoPayroll.java — the code in Listings 2-8 and 1-4. You’ll also find a file named EmployeeInfo.txt. That’s good, because if Java can't find the EmployeeInfo.txt file, the whole project doesn’t run properly. Instead, you get a FileNotFoundException.

In general, when you get a FileNotFoundException, some file that your program needs isn’t available to it. This is an easy mistake to make. It can be frustrating because to you, a file such as EmployeeInfo.txt may look like it’s available to your program. But remember — computers are stupid. If you make a tiny mistake, the computer can’t read between the lines for you. So if your EmployeeInfo.txt file isn’t in the right directory on your hard drive or the filename is spelled incorrectly, the computer chokes when it tries to run your code.

Sometimes you know darn well that an EmployeeInfo.txt (or whatever.xyz) file exists on your hard drive. But when you run your program, you still get a mean-looking FileNotFoundException. When this happens, the file is usually in the wrong directory on your hard drive. (Of course, it depends on your point of view. Maybe the file is in the right directory, but you’ve told your Java program to look for the file in the wrong directory.) When this happens, try copying the file to some other directories on your hard drive and rerunning your code. Carefully read and reread the names and locations of files on your hard drive until you figure out what’s wrong.

ontheweb_fmt.eps On this book's website (www.allmycode.com/JavaForDummies), you can find tips on the proper location of the EmployeeInfo.txt file. Look for tips that apply to your operating system (Windows, Macintosh, or Linux) and to your IDE (Eclipse, NetBeans, or IntelliJ IDEA).

Adding directory names to your filenames

You can specify a file’s exact location in your Java code. Code like new File("C:\Users\bburd\workspace\Listing08-01-02\EmployeeInfo.txt") looks really ugly, but it works.

In the previous paragraph, notice the double backslashes in "C: \Users\bburd\workspace . ..". If you’re a Windows user, you’d be tempted to write C:Usersburdworkspace . . . with single backslashes. But in Java, the single backslash has its own special meaning. (For example, back in Listing 7-7, means to go to the next line.) So in Java, to indicate a backslash inside a quoted string, you use a double backslash instead.

technicalstuff.eps Macintosh and Linux users might find comfort in the fact that their path separator, /, has no special meaning in a Java string. On a Mac, the code new File("/Users/bburd/workspace/Listing08-01-02/EmployeeInfo.txt") is as normal as breathing. (Well, it's almost that normal!) But Mac users and Linux wonks shouldn't claim superiority too quickly. Lines such as new File("/Users/bburd/workspace. . . work in Windows as well. In Windows, you can use either a slash (/) or a backslash () as your path name separator. In the Windows Command Prompt, I can type cd c:/usersburd to get to my home directory.

tip.eps If you know where your Java program looks for files, you can worm your way from that place to the directory of your choice. Assume, for the moment, that the code in Listing 8-2 normally looks for the EmployeeInfo.txt file in a directory named Listing08-01-02. So, as an experiment, go to the Listing08-01-02 directory and create a new subdirectory named dataFiles. Then move my EmployeeInfo.txt file to the new dataFiles directory. To read numbers and words from the file that you moved, modify Listing 8-2 with the code new File("dataFiles\EmployeeInfo.txt").

Reading a line at a time

In Listing 8-2, the payOneEmployee method illustrates some useful tricks for reading data. In particular, every scanner that you create has a nextLine method. (You might not use this nextLine method, but the method is available nonetheless.) When you call a scanner’s nextLine method, the method grabs everything up to the end of the current line of text. In Listing 8-2, a call to nextLine can read a whole line from the EmployeeInfo.txt file. (In another program, a scanner’s nextLine call may read everything the user types on the keyboard up to the pressing of the Enter key.)

Notice my careful choice of words: nextLine reads everything up to the end of the current line. Unfortunately, what it means to read up to the end of the current line isn’t always what you think it means. Intermingling nextInt, nextDouble, and nextLine calls can be messy. You have to watch what you’re doing and check your program’s output carefully.

To understand all this, you need to be painfully aware of a data file’s line breaks. Think of a line break as an extra character, stuck between one line of text and the next. Then imagine that calling nextLine means to read everything up to and including the next line break.

Now take a look at Figure 8-4.

  • If one call to nextLine reads Barry Burd[LineBreak], the subsequent call to nextLine reads CEO[LineBreak].
  • If one call to nextDouble reads the number 5000.00, the subsequent call to nextLine reads the [LineBreak] that comes immediately after the number 5000.00. (That’s all the nextLine reads — a [LineBreak] and nothing more.)
  • If a call to nextLine reads the [LineBreak] after the number 5000.00, the subsequent call to nextLine reads Harriet Ritter[LineBreak].
9781118407806-fg0804.tif

Figure 8-4: Calling nextDouble and nextLine.

So after reading the number 5000.00, you need two calls to nextLine in order to scoop up the name Harriet Ritter. The mistake that I usually make is to forget the first of those two calls.

warning.eps Look again at the file in Figure 8-3. For this section’s code to work correctly, you must have a line break after the last 10000.00. If you don’t, a final call to nextLine makes your program crash and burn. The error message reads NoSuchElementException: No line found.

technicalstuff.eps I’m always surprised by the number of quirks that I find in each programming language’s scanning methods. For example, the first nextLine that reads from the file in Figure 8-3 devours Barry Burd[LineBreak] from the file. But that nextLine call delivers Barry Burd (without any line break) to the running code. So nextLine looks for a line break, and then nextLine loses the line break. Yes, this is a subtle point. And no, this subtle point hardly ever causes problems for anyone.

technicalstuff.eps If this business about nextDouble and nextLine confuses you, please don’t put the blame on Java. Mixing input calls is delicate work in any computer programming language. And the really nasty thing is that each programming language approaches the problem a little differently. What you find out about nextLine in Java helps you understand the issues when you get to know C++ or Visual Basic, but it doesn’t tell you all the details. Each language’s details are unique to that language. (Yes, it’s a big pain. But because all computer programmers become rich and famous, the pain eventually pays off.)

Closing the connection to a disk file

To the average computer user, a keyboard doesn't feel anything like a file stored on a computer's hard drive. But disk files and keyboard input have a lot in common. In fact, a basic principle of computer operating systems dictates that, for the programmer, any differences between two kinds of input be as blurry as possible. As a Java programmer, you should treat disk files and keyboard input almost the same way. That's why Listing 8-2 contains a diskScanner.close() call.

When you run a Java program, you normally execute the main method's statements, starting with the first statement in the method body and ending with the last statement in the method body. You take detours along the way, skipping past else parts and diving into method bodies, but basically, you finish executing statements at the end of the main method. That's why, in Listing 8-2, the call to close is at the end of the main method's body. When you run the code in Listing 8-2, the last thing you do is disconnect from the disk file. And, fortunately, that disconnection takes place after you've executed all the nextLine and nextDouble calls.

Defining Subclasses (What It Means to Be a Full-Time or Part-Time Employee)

This time last year, your company paid $10 million for a piece of software. That software came in the Employee.class file. People at Burd Brain Consulting (the company that created the software) don’t want you to know about the innards of the software. (Otherwise, you may steal their ideas.) So you don’t have the Java program file that the software came from. (In other words, you don’t have Employee.java.) You can run the bytecode in the Employee.class file. You can also read the documentation in a web page named Employee.html. But you can’t see the statements inside the Employee.java program, and you can’t change any of the program’s code.

Since this time last year, your company has grown. Unlike the old days, your company now has two kinds of employees: full-time and part-time. Each full-time employee is on a fixed, weekly salary. (If the employee works nights and weekends, then in return for this monumental effort, the employee receives a hearty handshake.) In contrast, each part-time employee works for an hourly wage. Your company deducts an amount from each full-time employee’s paycheck to pay for the company’s benefits package. Part-time employees, however, don’t get benefits.

The question is whether the software that your company bought last year can keep up with the company’s growth. You invested in a great program to handle employees and their payroll, but the program doesn’t differentiate between your full-time and part-time employees. You have several options:

  • Call your next-door neighbor, whose 12-year-old child knows more about computer programming than anyone in your company. Get this uppity little brat to take the employee software apart, rewrite it, and hand it back to you with all the changes and additions your company requires.

    On second thought, you can’t do that. No matter how smart that kid is, the complexities of the employee software will probably confuse the kid. By the time you get the software back, it’ll be filled with bugs and inconsistencies. Besides, you don’t even have the Employee.java file to hand to the kid. All you have is the Employee.class file, which can’t be read or modified with a text editor. (See Chapter 2.) Besides, your kid just beat up the neighbor’s kid. You don’t want to give your neighbor the satisfaction of seeing you beg for the whiz kid’s help.

  • Scrap the $10 million employee software. Get someone in your company to rewrite the software from scratch.

    In other words, say goodbye to your time and money.

  • Write a new front end for the employee software. That is, build a piece of code that does some preliminary processing on full-time employees and then hands the preliminary results to your $10 million software. Do the same for part-time employees.

    This idea could be decent or spell disaster. Are you sure that the existing employee software has convenient hooks in it? (That is, does the employee software contain entry points that allow your front-end software to easily send preliminary data to the expensive employee software?) Remember, this plan treats the existing software as one big, monolithic lump, which can become cumbersome. Dividing the labor between your front-end code and the existing employee program is difficult. And if you add layer upon layer to existing black box code, you’ll probably end up with a fairly inefficient system.

  • Call Burd Brain Consulting, the company that sold you the employee software. Tell Dr. Burd that you want the next version of his software to differentiate between full-time and part-time employees.

    “No problem,” says Dr. Burd. “It’ll be ready by the start of the next fiscal quarter.” That evening, Dr. Burd makes a discreet phone call to his next-door neighbor….

  • Create two new Java classes named FullTimeEmployee and PartTimeEmployee. Have each new class extend the existing functionality of the expensive Employee class, but have each new class define its own specialized functionality for certain kinds of employees.

    Way to go! Figure 8-5 shows the structure that you want to create.

    9781118407806-fg0805.tif

    Figure 8-5: The Employee class family tree.

Creating a subclass

In Listing 8-1, I define an Employee class. I can use what I define in Listing 8-1 and extend the definition to create new, more specialized classes. So in Listing 8-3, I define a new class — a FullTimeEmployee class.

Listing 8-3: What Is a FullTimeEmployee?

  public class FullTimeEmployee extends Employee {
   private double weeklySalary;
   private double benefitDeduction;

   public void setWeeklySalary(double weeklySalaryIn) {
      weeklySalary = weeklySalaryIn;
   }

   public double getWeeklySalary() {
      return weeklySalary;
   }

   public void setBenefitDeduction(double benefitDedIn) {
      benefitDeduction = benefitDedIn;
   }

   public double getBenefitDeduction() {
      return benefitDeduction;
   }

   public double findPaymentAmount() {
      return weeklySalary - benefitDeduction;
   }
}

Looking at Listing 8-3, you can see that each instance of the FullTimeEmployee class has two fields: weeklySalary and benefitDeduction. But are those the only fields that each FullTimeEmployee instance has? No, they’re not. The first line of Listing 8-3 says that the FullTimeEmployee class extends the existing Employee class. This means that in addition to having a weeklySalary and a benefitDeduction, each FullTimeEmployee instance also has two other fields: name and jobTitle. These two fields come from the definition of the Employee class, which you can find in Listing 8-1.

In Listing 8-3, the magic word is extends. When one class extends an existing class, the extending class automatically inherits functionality that’s defined in the existing class. So, the FullTimeEmployee class inherits the name and jobTitle fields. The FullTimeEmployee class also inherits all the methods that are declared in the Employee class — setName, getName, setJobTitle, getJobTitle, and cutCheck. The FullTimeEmployee class is a subclass of the Employee class. That means the Employee class is the superclass of the FullTimeEmployee class. You can also talk in terms of blood relatives. The FullTimeEmployee class is the child of the Employee class, and the Employee class is the parent of the FullTimeEmployee class.

It’s almost (but not quite) as if the FullTimeEmployee class was defined by the code in Listing 8-4.

Listing 8-4: Fake (But Informative) Code

  import static java.lang.System.out;

public class FullTimeEmployee {
   private String name;
   private String jobTitle;
   private double weeklySalary;
   private double benefitDeduction;

   public void setName(String nameIn) {
      name = nameIn;
   }

   public String getName() {
      return name;
   }

   public void setJobTitle(String jobTitleIn) {
      jobTitle = jobTitleIn;
   }

   public String getJobTitle() {
      return jobTitle;
   }

   public void setWeeklySalary(double weeklySalaryIn) {
      weeklySalary = weeklySalaryIn;
   }

   public double getWeeklySalary() {
      return weeklySalary;
   }

   public void setBenefitDeduction(double benefitDedIn) {
      benefitDeduction = benefitDedIn;
   }

   public double getBenefitDeduction() {
      return benefitDeduction;
   }

   public double findPaymentAmount() {
      return weeklySalary - benefitDeduction;
   }

   public void cutCheck(double amountPaid) {
      out.printf("Pay to the order of %s ", name);
      out.printf("(%s) ***$", jobTitle);
      out.printf("%,.2f ", amountPaid);
   }
}

technicalstuff.eps Why does the title for Listing 8-4 call that code fake? (Should the code feel insulted?) Well, the main difference between Listing 8-4 and the inheritance situation in Listings 2-8 and 1-4 is this: A child class can’t directly reference the private fields of its parent class. To do anything with the parent class’s private fields, the child class has to call the parent class’s accessor methods. Back in Listing 8-3, calling setName("Rufus") would be legal, but the code name="Rufus" wouldn’t be. If you believe everything you read in Listing 8-4, you’d think that code in the FullTimeEmployee class can do name="Rufus". Well, it can’t. (My, what a subtle point this is!)

remember.eps You don’t need the Employee.java file on your hard drive to write code that extends the Employee class. All you need is the file Employee.class.

Creating subclasses is habit-forming

After you’re accustomed to extending classes, you can get extend-happy. If you created a FullTimeEmployee class, you might as well create a PartTimeEmployee class, as shown in Listing 8-5.

Listing 8-5: What Is a PartTimeEmployee?

  public class PartTimeEmployee extends Employee {
   private double hourlyRate;

   public void setHourlyRate(double rateIn) {
      hourlyRate = rateIn;
   }

   public double getHourlyRate() {
      return hourlyRate;
   }

   public double findPaymentAmount(int hours) {
      return hourlyRate * hours;
   }
}

Unlike the FullTimeEmployee class, PartTimeEmployee has no salary or deduction. Instead PartTimeEmployee has an hourlyRate field. (Adding a numberOfHoursWorked field would also be a possibility. I chose not to do this, figuring that the number of hours a part-time employee works will change drastically from week to week.)

Using Subclasses

The previous section tells a story about creating subclasses. It’s a good story, but it’s incomplete. Creating subclasses is fine, but you gain nothing from these subclasses unless you write code to use them. So in this section, you explore code that uses subclasses.

Now the time has come for you to classify yourself as either a type-F person, a type-P person, or a type-T person. (I'm this book's author so I get to make up some personality types. I can even point to someone in public and say, “Look! He's a type-T person!”)

  • A type-F person wants to see the fundamentals. (The letter F stands for fundamentals.) “Show me a program that lays out the principles in their barest, most basic form,” says the type-F person. A type-F person isn’t worried about bells and whistles. The bells come later, and the whistles may never come at all. If you’re a type-F person, you want to see a program that uses the FullTimeEmployee and PartTimeEmployee subclasses and then moves out of your way so you can get some work done.
  • A type-P person wants practical applications. (The letter P stands for practical.) Type-P people need to see ideas in context; otherwise, the ideas float away too quickly. “Show me a program that demonstrates the usefulness of the FullTimeEmployee and PartTimeEmployee subclasses,” says the type-P person. “I have no use for your stinking abstractions. I want real-life examples, and I want them now!”
  • A type-T person is inspired by something that I write about briefly in Chapter 7. The T person wants to test the code in the FullTimeEmployee and PartTimeEmployee subclasses. Testing the code means putting the code through its paces — checking the output's accuracy when the input is ordinary, when the input is unexpected, and even when the input is completely unrealistic. What's more, the type-T person wants to use a standard, easily recognizable outline for the testing code so that other programmers can quickly understand the test results. The type-T person creates JUnit tests that use the FullTimeEmployee and PartTimeEmployee subclasses.

Listing 8-6, which is for the type-F crowd, is lean and simple and makes good bedtime reading.

ontheweb_fmt.eps If you're a type-P or type-T person, please visit this book's website (www.allmycode.com/JavaForDummies). The site contains examples to satisfy type-P and type-T readers.

Listing 8-6 shows you a bare-bones program that uses the subclasses FullTimeEmployee and PartTimeEmployee. Figure 8-6 shows the program’s output.

Listing 8-6: Putting Subclasses to Good Use

  public class DoPayrollTypeF {

public static void main(String args[]) {

   FullTimeEmployee ftEmployee = new FullTimeEmployee();

   ftEmployee.setName("Barry Burd");
   ftEmployee.setJobTitle("CEO");
   ftEmployee.setWeeklySalary(5000.00);
   ftEmployee.setBenefitDeduction(500.00);
   ftEmployee.cutCheck(ftEmployee.findPaymentAmount());
   System.out.println();

   PartTimeEmployee ptEmployee = new PartTimeEmployee();

   ptEmployee.setName("Steve Surace");
   ptEmployee.setJobTitle("Driver");
   ptEmployee.setHourlyRate(7.53);
   ptEmployee.cutCheck
               (ptEmployee.findPaymentAmount(10));
}
}

9781118407806-fg0806.tif

Figure 8-6: The output of the program in Listing 8-6.

To understand Listing 8-6, you need to keep an eye on three classes: Employee, FullTimeEmployee, and PartTimeEmployee. (For a look at the code that defines these classes, see Listings 8-1, 8-3, and 8-5.)

The first half of Listing 8-6 deals with a full-time employee. Notice how so many methods are available for use with the ftEmployee variable. For instance, you can call ftEmployee.setWeeklySalary because ftEmployee has type FullTimeEmployee. You can also call ftEmployee.setName because the FullTimeEmployee class extends the Employee class.

Because cutCheck is declared in the Employee class, you can call ftEmployee.cutCheck. But you can also call ftEmployee.findPaymentAmount because a findPaymentAmount method is in the FullTimeEmployee class.

Making types match

Look again at the first half of Listing 8-6. Take special notice of that last statement — the one in which the full-time employee is actually cut a check. The statement forms a nice, long chain of values and their types. You can see this by reading the statement from the inside out.

  • Method ftEmployee.findPaymentAmount is called with an empty parameter list (Listing 8-6). That’s good because the findPaymentAmount method takes no parameters (Listing 8-3).
  • The findPaymentAmount method returns a value of type double (again, Listing 8-3).
  • The double value that ftEmployee.findPaymentAmount returns is passed to method ftEmployee.cutCheck (Listing 8-6). That’s good because the cutCheck method takes one parameter of type double (Listing 8-1).

For a fanciful graphic illustration, see Figure 8-7.

9781118407806-fg0807.tif

Figure 8-7: Matching parameters.

remember.eps Always feed a method the value types that it wants in its parameter list.

The second half of the story

In the second half of Listing 8-6, the code creates an object of type PartTime
­Employee. A variable of type PartTimeEmployee can do some of the same things a FullTimeEmployee variable can do. But the PartTimeEmployee class doesn’t have the setWeeklySalary and setBenefitDeduction methods. Instead, the PartTimeEmployee class has the setHourlyRate method. (See Listing 8-5.) So, in Listing 8-6, the next-to-last line is a call to the setHourlyRate method.

The last line of Listing 8-6 is by far the most interesting. On that line, the code hands the number 10 (the number of hours worked) to the findPaymentAmount method. Compare this with the earlier call to findPaymentAmount — the call for the full-time employee in the first half of Listing 8-6. Between the two subclasses, FullTimeEmployee and PartTimeEmployee, are two different findPaymentAmount methods. The two methods have two different kinds of parameter lists:

  • The FullTimeEmployee class’s findPaymentAmount method takes no parameters (Listing 8-3).
  • The PartTimeEmployee class’s findPaymentAmount method takes one int parameter (Listing 8-5).

This is par for the course. Finding the payment amount for a part-time employee isn’t the same as finding the payment amount for a full-time employee. A part-time employee’s pay changes each week, depending on the number of hours the employee works in a week. The full-time employee’s pay stays the same each week. So the FullTimeEmployee and PartTimeEmployee classes both have findPaymentAmount methods, but each class’s method works quite differently.

Overriding Existing Methods (Changing the Payments for Some Employees)

Wouldn’t you know it! Some knucklehead in the human resources department offered double pay for overtime to one of your part-time employees. Now word is getting around, and some of the other part-timers want double pay for their overtime work. If this keeps up, you’ll end up in the poorhouse, so you need to send out a memo to all the part-time employees, explaining why earning more money is not to their benefit.

In the meantime, you have two kinds of part-time employees — the ones who receive double pay for overtime hours and the ones who don’t — so you need to modify your payroll software. What are your options?

  • Well, you can dig right into the PartTimeEmployee class code, make a few changes, and hope for the best. (Not a good idea!)
  • You can follow the previous section’s advice and create a subclass of the existing PartTimeEmployee class. “But wait,” you say. “The existing PartTimeEmployee class already has a findPaymentAmount method. Do I need some tricky way of bypassing this existing findPaymentAmount method for each double-pay-for-overtime employee?”

    At this point, you can thank your lucky stars that you’re doing object-oriented programming in Java. With object-oriented programming, you can create a subclass that overrides the functionality of its parent class. Listing 8-7 has just such a subclass.

Listing 8-7: Yet Another Subclass

  public class PartTimeWithOver extends PartTimeEmployee {

   @Override
   public double findPaymentAmount(int hours) {

      if(hours <= 40) {
         return getHourlyRate() * hours;
      } else {
         return getHourlyRate() * 40 +
                 getHourlyRate() * 2 * (hours - 40);
      }
   }
}

Figure 8-8 shows the relationship between the code in Listing 8-7 and other pieces of code in this chapter. In particular, PartTimeWithOver is a subclass of a subclass. In object-oriented programming, a chain of this kind is not the least bit unusual. In fact, as subclasses go, this chain is rather short.

9781118407806-fg0808.tif

Figure 8-8: A tree of classes.

The PartTimeWithOver class extends the PartTimeEmployee class, but PartTimeWithOver picks and chooses what it wants to inherit from the PartTimeEmployee class. Because PartTimeWithOver has its own declaration for the findPaymentAmount method, the PartTimeWithOver class doesn’t inherit a findPaymentAmount method from its parent. (See Figure 8-9.)

9781118407806-fg0809.tif

Figure 8-9: Method findPayment Amount isn’t inherited.

According to the official terminology, the PartTimeWithOver class overrides its parent class’s findPaymentAmount method. If you create an object from the PartTimeWithOver class, that object has the name, jobTitle, hourlyRate, and cutCheck of the PartTimeEmployee class, but the object has the findPaymentAmount method that’s defined in Listing 8-7.

A Java annotation

The word @Override in Listing 8-7 is an example of an annotation. A Java annotation tells your computer something about your code. In particular, the @Override annotation in Listing 8-7 tells the Java compiler to be on the lookout for a common coding error. The annotation says, “Make sure that the method immediately following this annotation has the same stuff (the same name, the same parameters, and so on) as one of the methods in the superclass. If not, then display an error message.”

So if I accidentally type

  public double findPaymentAmount(double hours) {

instead of int hours as in Listings 2-8 and 5-4, the compiler reminds me that my new findPaymentAmount method doesn't really override anything that's in Listing 8-5.

Java has other kinds of annotations (such as @Deprecated and @Suppress
Warnings). You can read a bit about the @SuppressWarnings annotation in Chapter 9.

technicalstuff.eps Java's annotations are optional. If you remove the word @Override from Listing 8-7, then your code still runs correctly. But the @Override annotation gives your code some added safety. With @Override, the compiler checks to make sure that you're doing something that you intend to do (namely, overriding one of the superclass's methods). And with apologies to George Orwell, some types of annotations are less optional than others. You can omit certain annotations from your code only if you're willing to replace the annotation with lots and lots of unannotated Java code.

Using methods from classes and subclasses

If you need clarification on this notion of overriding a method, look at the code in Listing 8-8. A run of that code is shown in Figure 8-10.

Listing 8-8: Testing the Code from Listing 8-7

  public class DoPayrollTypeF {

public static void main(String args[]) {

   FullTimeEmployee ftEmployee = new FullTimeEmployee();

   ftEmployee.setName("Barry Burd");
   ftEmployee.setJobTitle("CEO");
   ftEmployee.setWeeklySalary(5000.00);
   ftEmployee.setBenefitDeduction(500.00);
      ftEmployee.cutCheck(ftEmployee.findPaymentAmount());

   PartTimeEmployee ptEmployee = new PartTimeEmployee();

   ptEmployee.setName("Chris Apelian");
   ptEmployee.setJobTitle("Computer Book Author");
   ptEmployee.setHourlyRate(7.53);
      ptEmployee.cutCheck
                 (ptEmployee.findPaymentAmount(50));

   PartTimeWithOver ptoEmployee =
                          new PartTimeWithOver();

   ptoEmployee.setName("Steve Surace");
   ptoEmployee.setJobTitle("Driver");
   ptoEmployee.setHourlyRate(7.53);
      ptoEmployee.cutCheck
                (ptoEmployee.findPaymentAmount(50));
}
}

9781118407806-fg0810.tif

Figure 8-10: Running the code of Listing 8-8.

The code in Listing 8-8 writes checks to three employees. The first employee is a full-timer. The second is a part-time employee who hasn’t yet gotten wind of the overtime payment scheme. The third employee knows about the overtime payment scheme and demands a fair wage.

With the subclasses, all three of these employees coexist in Listing 8-8. Sure, one subclass comes from the old PartTimeEmployee class, but that doesn’t mean you can’t create an object from the PartTimeEmployee class. In fact, Java is very smart about this. Listing 8-8 has three calls to the findPaymentAmount method, and each call reaches out to a different version of the method.

  • In the first call, ftEmployee.findPaymentAmount, the ftEmployee variable is an instance of the FullTimeEmployee class. So the method that’s called is the one in Listing 8-3.
  • In the second call, ptEmployee.findPaymentAmount, the ptEmployee variable is an instance of the PartTimeEmployee class. So the method that’s called is the one in Listing 8-5.
  • In the third call, ptoEmployee.findPaymentAmount, the ptoEmployee variable is an instance of the PartTimeWithOver class. So the method that’s called is the one in Listing 8-7.

This code is fantastic. It’s clean, elegant, and efficient. With all the money that you save on software, you can afford to pay everyone double for overtime hours. (Whether you do that or keep the money for yourself is another story.)

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.138.34.226