Packaging and Documenting Your Classes
Now that you know just about everything there is to know about creating classes, this chapter shows you what to do with the classes you create. Specifically, I show you how to organize your classes into neat packages. Packages enable you to keep your classes separate from classes in the Java API, allow you to reuse your classes in other applications, and even let you distribute your classes to others, assuming other people might be interested in your classes.
If that's the case, you probably won't want to just send those people all your separate class files. Instead, you want to bundle them into a single file called a JAR file. That's covered in this chapter too.
Finally, you find out how to use a feature called JavaDocs that lets you add documentation comments to your classes. With JavaDocs, you can build professional-looking documentation pages automatically. Your friends will think you're a real Java guru when you post your JavaDoc pages to your Web site.
Working with Packages
A package is a group of classes that belong together. Without packages, the entire universe of Java classes would be a huge unorganized mess. Imagine the thousands of classes that are available in the Java API combined with millions of Java classes created by Java programmers throughout the world, all thrown into one big pot. Packages let you organize this pot into smaller, manageable collections of related classes.
Importing classes and packages
When you use import statements at the beginning of a Java source file, you make classes from the packages mentioned in the import statements available throughout the file. (I cover import statements in Book II, Chapter 1, but it doesn't hurt to repeat it here.)
An import statement can import all the classes in a package by using an asterisk wildcard:
import java.util.*;
Here all the classes in the java.util package are imported.
Alternatively, you can import classes one at a time:
import java.util.ArrayList;
Here just the ArrayList class is imported.
Note |
You don't have to use an import statement to use a class from a package. But if you don't use an import statement, you must fully qualify any references to the class. For example, you can use the ArrayList class without importing java.util: java.util.ArrayList = new java.util.ArrayList(); |
Because fully qualified names are a pain to always spell out, you should always use import statements to import the packages or individual classes your application uses.
You never have to explicitly import two packages:
- java.lang: This package contains classes that are so commonly used that the Java compiler makes them available to every program. Examples of the classes in this package are String, Exception, and the various wrapper classes, such as Integer and Boolean.
- The default package: This package contains classes that aren't specifically put in some other package. All the programs I show in this book up to this point rely on the default package.
For simple program development and experimentation, using the default package is acceptable. However, if you start work on a serious Java application, create a separate package for it and place all the application's classes there. You find out how to do that in the next section.
TECHNICAL STAUFF |
You can't import the default package, even if you want to. Suppose you have two packages-the default package and the com.lowewriter.util package. The default package's code contains the statement import com.lowewriter.util.*. That's okay. But the default package doesn't have a name-at least it has no name that you can use inside a program. The com.lowewriter.util package's code can't contain a statement like import that_default_package.you_know.the_one_with_no_name. |
Creating your own packages
Creating your own packages to hold your classes is easy. Well, relatively easy anyway. You must go through a few steps:
- Pick a name for your package.
You can use any name you wish, but I recommend you follow the established convention of using your Internet domain name (if you have one), only backwards. I own a domain called http://www.LoweWriter.com, so I use the name com.lowewriter for all my packages. (Using your domain name backwards ensures that your package names are unique.)
Notice that package names are in all-lowercase letters. That's not an absolute requirement, but it's a Java convention that you ought to stick to. If you start using capital letters in your package names, you'll be branded a rebel for sure.
Tip You can add additional levels beyond the domain name if you want. For example, I put my utility classes in a package named com.lowewriter. util.
If you don't have a domain all to yourself, try using your e-mail address backwards. For example, if your e-mail address is SomeBody@SomeCompany.com, use com.somecompany.somebody for your package names. That way they are still unique. (If you ever want to distribute your Java packages, you should register a domain name. Nothing says "Amateur" like a package name that starts with com.aol.)
- Choose a directory on your hard drive to be the root of your class library.
You need a place on your hard drive to store your classes. I suggest you create a directory such as c:javaclasses.
This folder becomes the root directory for your Java packages.
- Create subdirectories within the root directory for your package name.
For example, for the package named com.lowewriter.util, create a directory named com in the c:javaclasses directory (assuming that's the name of your root). Then, in the com directory, create a directory named lowewriter. Then, in lowewriter, create a directory named util. Thus, the complete path to the directory that contains the classes for the com.lowewriter.util package is c:javaclasses comlowewriterutil.
- Add the root directory for your package to the ClassPath environment variable.
The exact procedure for doing this depends on your operating system. In Windows XP and Vista, you can set the ClassPath by double-clicking System from the Control Panel. Click the Advanced tab, and then click Environment Variables.
Be careful not to disturb any directories already listed in the ClassPath. To add your root directory to the ClassPath, add a semicolon followed by the path to your root directory to the end of the ClassPath value. For example, suppose your ClassPath is already set to this:
.;c:utilclasses
Then you modify it to look like this:
.;c:utilclasses;c:javaclasses
Here I added ;c:javaclasses to the end of the ClassPath value.
- Save the files for any classes you want to be in a particular package in the directory for that package.
For example, save the files for a class that belongs to the com.lowewriter.util package in c:javaclassescom lowewriterutil.
- Add a package statement to the beginning of each source file that belongs in a package.
The package statement simply provides the name for the package that any class in the file is placed in. For example:
package com.lowewriter.util;
REMEMBER The package statement must be the first non-comment statement in the file.
An example
Suppose you've developed a utility class named Console that has a bunch of handy static methods for getting user input from the console. For example, this class has a static method named askYorN that gets a Y or N from the user and returns a boolean value to indicate which value the user entered. You decide to make this class available in a package named com.lowewriter.util so you and other like-minded programmers can use it in their programs.
Here's the source file for the Console class:
package com.lowewriter.util; import java.util.Scanner; public class Console { static Scanner sc = new Scanner(System.in); public static boolean askYorN(String prompt) { while (true) { String answer; System.out.print(" " + prompt + " (Y or N) "); answer = sc.next(); if (answer.equalsIgnoreCase("Y")) return true; else if (answer.equalsIgnoreCase("N")) return false; } } }
Okay, so far this class has just the one method (askYorN), but one of these days you'll add a bunch of other useful methods to it. In the meantime, you want to get it set up in a package so you can start using it right away.
So you create a directory named c:javaclassescomlowewriterutil (as described in the preceding section) and save the source file to this directory. Then you compile the program so the Console.class file is stored in that directory too. And you add c:javaclasses to your ClassPath environment variable.
Now you can use the following program to test that your package is alive and well:
import com.lowewriter.util.*; public class PackageTest { public static void main(String[] args) { while (Console.askYorN("Keep going?")) { System.out.println("D'oh!"); } } }
Here the import statement imports all the classes in the com.lowewriter. util package. Then, the while loop in the main method repeatedly asks the user if he or she wants to keep going.
Putting Your Classes in a JAR File
A JAR file is a single file that can contain more than one class in a compressed format that the Java Runtime Environment can access quickly. (JAR stands for Java archive.) A JAR file can have just a few classes in it, or thousands. In fact, the entire Java API is stored in a single JAR file named rt.java. (The rt stands for runtime.) It's a pretty big file-over 35MB-but that's not bad considering that it contains more than 12,000 classes.
JAR files are created by the jar utility, which you find in the Java bin directory along with the other Java command line tools, such as java and javac. JAR files are similar in format to Zip files, a compressed format made popular by the PKZIP program. The main difference is that JAR files contain a special file, called the manifest file, that contains information about the files in the archive. This manifest is automatically created by the jar utility, but you can supply a manifest of your own to provide additional information about the archived files.
JAR files are the normal way to distribute finished Java applications. After finishing your application, you run the jar command from a command prompt to prepare the JAR file. Then, another user can copy the JAR file to his or her computer. The user can then run the application directly from the JAR file.
JAR files are also used to distribute class libraries. You can add a JAR file to the ClassPath environment variable. Then, the classes in the JAR file are automatically available to any Java program that imports the package that contains the classes.
jar command line options
The jar command is an old-fashioned Unix-like command, complete with arcane command-line options that you have to get right if you expect to coax jar into doing something useful.
The basic format of the jar command is this:
jar options jar-file [manifest-file] class-files...
The options specify the basic action you want jar to perform and provide additional information about how you want the command to work. Table 8-1 lists the options.
Option |
Description |
---|---|
c |
Creates a new jar file. |
u |
Updates an existing jar file. |
x |
Extracts files from an existing jar file. |
t |
Lists the contents of a jar file. |
f |
Indicates that the jar file is specified as an argument. You almost always want to use this option. |
v |
Verbose output. This option tells the jar command to display extra information while it works. |
0 |
Doesn't compress files when it adds them to the archive. This option isn't used much. |
m |
Specifies that a manifest file is provided. It's listed as the next argument following the jar file. |
M |
Specifies that a manifest file should not be added to the archive. This option is rarely used. |
Note that you must specify at least the c, u, x, or t option to tell jar what action you want to perform.
Archiving a package
The most common use for the jar utility is to create an archive of an entire package. The procedure for doing that varies slightly depending on what operating system you're using. However, the jar command itself is the same regardless of your operating system. Here's the procedure for archiving a package on a PC running Windows XP:
- Open a command window.
The easiest way to do that is to choose Start Run, type cmd in the Open text box, and click OK.
- Use a cd command to navigate to your package root.
For example, if your packages are stored in c:javaclasses, use this command:
cd javaclasses
- Use a jar command that specifies the options cf, the name of the jar file, and the path to the class files you want to archive.
For example, to create an archive named utils.jar that contains all the class files in the com.lowewriter.util package, use this command:
jar cf utils.jar comlowewriterutil*.class
- To verify that the jar file was created correctly, use the jar command that specifies the options tf and the name of the jar file.
For example, if the jar file is named utils.jar, use this command:
jar tf utils.jar
This lists the contents of the jar file so you can see what classes were added. Here's some typical output from this command:
META-INF/ META-INF/MANIFEST.MF com/lowewriter/util/Console.class com/lowewriter/util/Random.class
As you can see, the utils.jar file contains the two classes in my com.lowewriter.util package, Console and Random.
- That's all!
You're done. You can leave the jar file where it is, or you can give it to your friends so they can use the classes it contains.
Adding a jar to your classpath
To use the classes in an archive, you must add the jar file to your ClassPath environment variable. I describe the procedure for modifying the ClassPath variable in Windows XP earlier in this chapter, in the section "Creating your own packages." So I won't repeat the details here.
To add an archive to the ClassPath variable, just add the complete path to the archive, making sure to separate it from any other paths already in the ClassPath with a semicolon. Here's an example:
.;c:javaclassesutils.jar;c:javaclasses
Here I added the path c:javaclassesutils.jar to my ClassPath variable.
Starting with Java 1.6, you can add all the jar files from a particular directory to the ClassPath in one fell swoop. For example, imagine that your c:javaclasses directory contains two jar files-utils.jar and extras.jar. To add both jar files to the ClassPath, use a forward slash (/) followed by an asterisk:
.;c:javaclasses/*
The forward slash looks strange, especially when combined with the backslash in c:javaclasses. But that's the way you use a ClassPath wildcard.
REMEMBER |
The first path in a ClassPath variable is always a single dot (.), which allows Java to find classes in the current directory. |
Tip |
Also, be aware that Java searches the various paths and archive files in the ClassPath variable in the order in which you list them. Thus, with the ClassPath.;c:javaclassesutils.jar;c:javaclasses, Java searches for classes first in the current directory, then in the utils archive, and finally in the c:javaclasses directory. |
Running a program directly from an archive
With just a little work, you can set up an archive so that a Java program can be run directly from it. All you have to do is create a manifest file before you create the archive. Then, when you run the jar utility to create the archive, you include the manifest file on the jar command line.
A manifest file is a simple text file that contains information about the files in the archive. Although it can contain many lines of information, it needs just one line to make an executable jar file:
Main-Class: ClassName
The ClassName is the fully qualified name of the class that contains the main method that is executed to start the application. It isn't required, but it's typical to use the extension .mf for manifest files.
For example, suppose you have an application whose main class is GuessingGame, and all the class files for the application are in the package com.lowewriter.game. First, create a manifest file named game.mf in the comlowewritergame directory. This file contains the following line:
Main-Class: com.lowewriter.game.GuessingGame
Then run the jar command with the options cfm, the name of the archive to create, the name of the manifest file, and the path for the class files. Here's an example:
jar cfm game.jar comlowewritergamegame.mf comlowewritergame*.class
Now you can run the application directly from a command prompt by using the java command with the -jar switch and the name of the archive file. Here's an example:
java -jar game.jar
This command starts the JRE and executes the main method of the class specified by the manifest file in the game.jar archive file.
Tip |
If your operating system is configured properly, you can also run the application by double-clicking an icon for the jar file. |
Using JavaDoc to Document Your Classes
One last step remains before you can go public with your hot new class library or application: preparing the documentation for its classes. Fortunately, Java provides a tool called JavaDoc that can automatically create fancy HTML-based documentation based on comments in your source files. All you have to do is add a comment for each public class, field, and method, run the source files through the javadoc command and, voilá! you have professional-looking Web-based documentation for your classes.
The following sections show you how to add JavaDoc comments to your source files, how to run the source files through the javadoc command, and how to view the resulting documentation pages.
Adding JavaDoc comments
The basic rule for creating JavaDoc comments is that they begin with /** and end with */. You can place JavaDoc comments in any of three different locations in a source file:
- Immediately before the declaration of a public class
- Immediately before the declaration of a public field
- Immediately before the declaration of a public method or constructor
A JavaDoc comment can include text that describes the class, field, or method. Each subsequent line of a multi-line JavaDoc comment usually begins with an asterisk. JavaDoc ignores this asterisk and any white space between it and the first word on the line.
The text in a JavaDoc comment can include HTML markup if you want to apply fancy formatting. You should avoid using heading tags (
and so on), because JavaDoc creates those, and your heading tags just confuse things. But you can use tags for boldface and italics (and) or to format code examples (use the
tag).
In addition, you can include special doc tags that provide specific information used by JavaDoc to format the documentation pages. Table 8-2 summarizes the most commonly used tags.
Tag |
Explanation |
---|---|
@author |
Provides information about the author, typically the author's name, e-mail address, Web site information, and so on. |
@version |
The version number. |
@since |
Used to indicate the version with which this class, field, or method was added. |
@param |
Provides the name and description of a method or constructor. |
@return |
Provides a description of a method's return value. |
@throws |
Indicates exceptions that are thrown by a method or constructor. |
@deprecated |
Indicates that the class, field, or method is deprecated and shouldn't be used. |
To give you an idea of how JavaDoc comments are typically used, Listing 8-1 shows an Employee class with JavaDoc comments included.
Listing 8-1: An Employee Class with JavaDoc Comments
package com.lowewriter.payroll; /** Represents an employee. * @author Doug Lowe * @author www.LoweWriter.com * @version 1.5 * @since 1.0 */ public class Employee { private String lastName; private String firstName; private Double salary; /** Represents the employee's address. */ public Address address; /** Creates an employee with the specified name. * @param lastName The employee's last name. * @param firstName The employee's first name. */ public Employee(String lastName, String firstName) { this.lastName = lastName; this.firstName = firstName; this.address = new Address(); } /** Gets the employee's last name. * @return A string representing the employee's last * name. */ public String getLastName() { return this.lastName; } /** Sets the employee's last name. * @param lastName A String containing the the employee's * last name. * @return No return value. */ public void setLastName(String lastName) { this.lastName = lastName; } /** Gets the employee's first name. * @return A string representing the employee's first * name. */ public String getFirstName() { return this.firstName; } /** Sets the employee's first name. * @param firstName A String containing the * employee's * @return No return value. */ public void setFirstName(String firstName) { this.firstName = firstName; } /** Gets the employee's Salary. * @return A double representing the employee's salary. */ public double getSalary() { return this.salary; } /** Sets the employee's Salary. * @param lastName A double containing the employee's * salary. * @return No return value. */ public void setSalary(double salary) { this.salary = salary; } }
Using the javadoc command
The javadoc command has a few dozen options you can set, making it a complicated command to use. However, you can ignore all these options to create a basic set of documentation pages. Just specify the complete path to all the Java files you want to create documentation for, like this:
javadoc comlowewriterpayroll*.java
The javadoc command creates the documentation pages in the current directory, so you may want to switch to the directory where you want the pages to reside first.
For more complete information about using this command, refer to the javadoc documentation at the Sun Web site. You can find it here:
Viewing JavaDoc pages
After you run the javadoc command, you can access the documentation pages by starting with the index.html page. To quickly display this page, just type index.html at the command prompt after you run the javadoc command. Or you can start your browser, navigate to the directory where you created the documentation pages, and open the index.html page. Either way, Figure 8-1 shows an index page that lists two classes.
If you think this page looks familiar, that's because the documentation for the Java API was created using JavaDocs. So you should already know how to find your way around these pages.
To look at the documentation for a class, click the class name's link. A page with complete documentation for the class comes up. For example, Figure 8-2 shows part of the documentation page for the Employee class. JavaDocs generated this page from the source file shown in Listing 8-1.
Figure 8-1: A JavaDocs index page.
Figure 8-2: Documentation for the Employee class.