This chapter explains a number of important and useful Java programming and documentation conventions. It covers:
General naming and capitalization conventions
Portability tips and conventions
javadoc documentation comment syntax and conventions
The following widely adopted naming conventions apply to modules, packages, reference types, methods, fields, and constants in Java. Because these conventions are almost universally followed and because they affect the public API of the classes you define, you should adopt them as well:
As modules are the preferred unit of distribution for Java applications from Java 9 onward, you should take special care when naming them.
Module names must be globally unique—the modules system is essentially predicated on this assumption. As modules are effectively super-packages (or aggregates of packages) the module name should be closely related to the package names that are grouped into the module. One recommended way to do this is to group together the packages within a module, and use the root name of the packages as the module name.
It is customary to ensure that your publicly visible package names are unique.
One common way of doing this is by prefixing them with the inverted name of an internet domain that you own (e.g., com.oreilly.javanutshell).
This convention is now followed less strictly than it used to be, with some projects merely adopting a simple, recognizable, and unique prefix instead. All package names should be lowercase.
A type name should begin with a capital letter and be written in
mixed case (e.g., String).
If a class name consists of more than one word, each word should begin with a capital letter (e.g., StringBuffer).
If a type name, or one of the words of a type name, is an acronym, the acronym can be written in all capital letters (e.g., URL, HTMLParser).
Because classes and enumerated types are designed to represent
objects, you should choose class names that are nouns (e.g., Thread,
Teapot, FormatConverter).
Enum types are a special case of a class where there are only finitely many instances.
They should be named as nouns in all but highly exceptional circumstances.
The constants defined by enum types are also typically written in all capital letters, as per the rules for constants below.
Java programmers typically use interfaces in one of two ways: either to convey that a class has additional, supplementary aspects or behaviors; or to indicate that the class is one possible implementation of an interface for which there are multiple valid implementation choices.
When an interface is used to provide additional information about the classes that implement it, it is common to choose an interface name that is an adjective (e.g., Runnable, Cloneable, Serializable).
When an interface is intended to work more like an abstract superclass, use a name that is a noun (e.g., Document, FileNameMap, Collection).
A method name always begins with a lowercase letter. If the name
contains more than one word, every word after the first begins with a
capital letter (e.g., insert(), insertObject(),
insertObjectAt()). This is usually referred to as camel case.
Method names are typically chosen so that the first word is a verb.
Method names can be as long as is necessary to make their purpose
clear, but choose succinct names where possible. Avoid overly general
method names, such as performAction(), go(), or the dreadful
doIt().
Nonconstant field names follow the same capitalization conventions as method names. A field name should be chosen to best describe the purpose of the field or the value it holds.
If a field is a static final constant, it should be written in all uppercase.
If the name of a constant includes more than one word, the words should be separated with underscores (e.g., MAX_VALUE).
Method parameters follow the same capitalization conventions as
nonconstant fields. The names of method parameters appear in the
documentation for a method, so you should choose names that make the
purpose of the parameters as clear as possible. Try to keep parameter
names to a single word and use them consistently. For example, if a
WidgetProcessor class defines many methods that accept a Widget
object as the first parameter, name this parameter widget.
Local variable names are an implementation detail and never visible outside your class. Nevertheless, choosing good names makes your code easier to read, understand, and maintain. Variables are typically named following the same conventions as methods and fields.
In addition to the conventions for specific types of names, there are
conventions regarding the characters you should use in your names.
Java allows the $ character in any identifier, but, by convention,
its use is reserved for synthetic names generated by source-code
processors. For example, it is used by the Java compiler to make inner
classes work. You should not use the $ character in any name that
you create.
Java allows names to use any alphanumeric characters from the entire Unicode character set. While this can be convenient for non-English-speaking programmers, this has never really taken off and this usage is extremely rare.
The names we give to our constructs matter—a lot. Naming is a key part of the process that conveys our abstract designs to our peers. The process of transferring a software design from one human mind to another is hard—harder, in many cases, than the process of transferring our design from our mind to the machines that will execute it.
We must, therefore, do everything we can to ensure that this process is eased. Names are a keystone of this. When reviewing code (and all code should be reviewed), pay particular attention to the names that have been chosen:
Do the names of the types reflect the purpose of those types?
Does each method do exactly what its name suggests? Ideally, no more, and no less?
Are the names descriptive enough? Could a more specific name be used instead?
Are the names well suited for the domain they describe?
Are the names consistent across the domain?
Do the names mix metaphors?
Does the name reuse a common term of software engineering?
Mixed metaphors are common in software, especially after several
releases of an application. A system that starts off perfectly
reasonably with components called Receptionist (for handling incoming
connections), Scribe (for persisting orders), and Auditor (for
checking and reconciling orders) can quite easily end up in a later
release with a class called Watchdog for restarting processes. This
isn’t terrible, but it breaks the established pattern of people’s job
titles that previously existed.
It is also incredibly important to realize that software changes a lot over time. A perfectly apposite name on release 1 can become highly misleading by release 4. Care should be taken that as the system focus and intent shifts, the names are refactored along with the code. Modern IDEs have no problem with global search and replace of symbols, so there is no need to cling to outdated metaphors once they are no longer useful.
One final note of caution: an overly strict interpretation of these guidelines can lead the developer to some very odd naming constructs. There are a number of excellent descriptions of some of the absurdities that can result by taking these conventions to their extremes.
In other words, none of the conventions described here is mandatory. Following them will, in the vast majority of cases, make your code easier to read and maintain. However, you should not be afraid to deviate from these guidelines if it makes your code easier to read and understand.
Break any of these rules rather than say anything outright barbarous.
George Orwell
Above all, you should have a sense of the expected lifetime of the code you are writing. A risk calculation system in a bank may have a lifetime of a decade or more, whereas a prototype for a startup may only be relevant for a few weeks. Document accordingly—the longer the code is likely to be live, the better its documentation needs to be.
Most ordinary comments within Java code explain the implementation details of that code. By contrast, the Java language specification defines a special type of comment known as a doc comment that serves to document the API of your code.
A doc comment is an ordinary multiline comment that begins with /**
(instead of the usual /*) and ends with */. A doc comment appears
immediately before a type or member definition and contains
documentation for that type or member. The documentation can include
simple HTML formatting tags and other special keywords that provide
additional information.
Doc comments are ignored by the compiler, but
they can be extracted and automatically turned into online HTML
documentation by the javadoc program. (See
Chapter 13 for more information about javadoc.)
Here is an example class that contains appropriate doc comments:
/*** This immutable class represents <i>complex numbers</i>.** @author David Flanagan* @version 1.0*/publicclassComplex{/*** Holds the real part of this complex number.* @see #y*/protecteddoublex;/*** Holds the imaginary part of this complex number.* @see #x*/protecteddoubley;/*** Creates a new Complex object that represents the complex number* x+yi. @param x The real part of the complex number.* @param y The imaginary part of the complex number.*/publicComplex(doublex,doubley){this.x=x;this.y=y;}/*** Adds two Complex objects and produces a third object that* represents their sum.* @param c1 A Complex object* @param c2 Another Complex object* @return A new Complex object that represents the sum of* <code>c1</code> and <code>c2</code>.* @exception java.lang.NullPointerException* If either argument is <code>null</code>.*/publicstaticComplexadd(Complexc1,Complexc2){returnnewComplex(c1.x+c2.x,c1.y+c2.y);}}
The body of a doc comment should begin with a one-sentence summary of the type or member being documented. This sentence may be displayed by itself as summary documentation, so it should be written to stand on its own. The initial sentence may be followed by any number of other sentences and paragraphs that describe the class, interface, method, or field in full detail.
After the descriptive paragraphs, a doc comment can contain any number
of other paragraphs, each of which begins with a special doc-comment
tag, such as @author, @param, or @returns. These tagged paragraphs
provide specific information about the class, interface, method, or
field that the javadoc program displays in a standard way. The full
set of doc-comment tags is listed in the next section.
The descriptive material in a doc comment can contain simple HTML markup
tags, such as <i> for emphasis; <code> for class, method, and field
names; and <pre> for multiline code examples. It can also contain
<p> tags to break the description into separate paragraphs and <ul>,
<li>, and related tags to display bulleted lists and similar
structures. Remember, however, that the material you write is embedded
within a larger, more complex HTML document. For this reason, doc
comments should not contain major structural HTML tags, such as <h2>
or <hr>, that might interfere with the structure of the larger
document.
Avoid the use of the <a> tag to include hyperlinks or cross-references
in your doc comments. Instead, use the special {@link} doc-comment
tag, which, unlike the other doc-comment tags, can appear anywhere
within a doc comment. As described in the next section, the {@link}
tag allows you to specify hyperlinks to other classes, interfaces,
methods, and fields without knowing the HTML-structuring conventions and
filenames used by javadoc.
If you want to include an image in a doc comment, place the image file
in a doc-files subdirectory of the source code directory. Give the
image the same name as the class, with an integer suffix. For example,
the second image that appears in the doc comment for a class named
Circle can be included with this HTML tag:
<imgsrc="doc-files/Circle-2.gif">
Because the lines of a doc comment are embedded within a Java comment,
any leading spaces and asterisks (*) are stripped from each line of
the comment before processing. Thus, you don’t need to worry about the
asterisks appearing in the generated documentation or about the
indentation of the comment affecting the indentation of code examples
included within the comment with a <pre> tag.
The javadoc program recognizes a number of special tags, each of
which begins with an @ character. These doc-comment tags allow you to
encode specific information into your comments in a standardized way,
and they allow javadoc to choose the appropriate output format for
that information. For example, the @param tag lets you specify the
name and meaning of a single parameter for a method. javadoc can
extract this information and display it using an HTML <dl> list, an
HTML <table>, or whatever it sees fit.
The following doc-comment tags are recognized by javadoc; a doc
comment should typically use these tags in the order listed here:
@author nameAdds an “Author:” entry that contains the specified name. This tag
should be used for every class or interface definition but must not be
used for individual methods and fields. If a class has multiple
authors, use multiple @author tags on adjacent lines. For example:
@authorBenEvans@authorDavidFlanagan
List the authors in chronological order, with the original author
first. If the author is unknown, you can use “unascribed.” javadoc
does not output authorship information unless the -author
command-line argument is specified.
@version textInserts a “Version:” entry that contains the specified text. For example:
@version1.32,08/26/04
This tag should be included in every class and interface doc comment
but cannot be used for individual methods and fields. This tag is
often used in conjunction with the automated version-numbering
capabilities of a version control system, such as git, Perforce, or
SVN. javadoc does not output version information in its generated
documentation unless the -version command-line argument is
specified.
@param parameter-name descriptionAdds the specified parameter and its description to the “Parameters:”
section of the current method. The doc comment for a method or
constructor must contain one @param tag for each parameter the
method expects. These tags should appear in the same order as the
parameters specified by the method. The tag can be used only in doc
comments for methods and constructors.
You are encouraged to use phrases and sentence fragments where possible to keep the descriptions brief. However, if a parameter requires detailed documentation, the description can wrap onto multiple lines and include as much text as necessary. For readability in source-code form, consider using spaces to align the descriptions with each other. For example:
@paramotheobjecttoinsert@paramindexthepositiontoinsertitat
@return descriptionInserts a “Returns:” section that contains the specified description.
This tag should appear in every doc comment for a method, unless the
method returns void or is a constructor. The description can be as
long as necessary, but consider using a sentence fragment to keep it
short. For example:
@return<code>true</code>iftheinsertionissuccessful,or<code>false</code>ifthelistalreadycontainstheobject.
@exception full-classname descriptionAdds a “Throws:” entry that contains the specified exception name and
description. A doc comment for a method or constructor should contain
an @exception tag for every checked exception that appears in its
throws clause. For example:
@exceptionjava.io.FileNotFoundExceptionIfthespecifiedfilecouldnotbefound
The @exception tag can optionally be used to document unchecked
exceptions (i.e., subclasses of RuntimeException) the method may
throw, when these are exceptions that a user of the method may
reasonably want to catch. If a method can throw more than one
exception, use multiple @exception tags on adjacent lines and list
the exceptions in alphabetical order. The description can be as short
or as long as necessary to describe the significance of the exception.
This tag can be used only for method and constructor comments. The
@throws tag is a synonym for @exception.
@throws full-classname descriptionThis tag is a synonym for @exception.
@see referenceAdds a “See Also:” entry that contains the specified reference. This
tag can appear in any kind of doc comment. The syntax for the
reference is explained in
“Cross-References in Doc Comments”.
@deprecated explanationThis tag specifies that the following type or member has been
deprecated and that its use should be avoided. javadoc adds a
prominent “Deprecated” entry to the documentation and includes the
specified explanation text. This text should specify when the
class or member was deprecated and, if possible, suggest a replacement
class or member and include a link to it. For example:
@deprecatedAsofVersion3.0,thismethodisreplacedby{@link#setColor}.
The @deprecated tag is an exception to the general rule that javac
ignores all comments. When this tag appears, the compiler notes the
deprecation in the class file it produces. This allows it to issue
warnings for other classes that rely on the deprecated feature.
@since versionSpecifies when the type or member was added to the API. This tag should be followed by a version number or other version specification. For example:
@sinceJNUT3.0
Every doc comment for a type should include an @since tag, and any
members added after the initial release of the type should have
@since tags in their doc comments.
@serial descriptionTechnically, the way a class is serialized is part of its public
API. If you write a class that you expect to be serialized, you should
document its serialization format using @serial and the related tags
listed next. @serial should appear in the doc comment for any field
that is part of the serialized state of a Serializable class.
For classes that use the default serialization mechanism, this means
all fields that are not declared transient, including fields
declared private. The description should be a brief description
of the field and of its purpose within a serialized object.
You can also use the @serial tag at the class and package level to
specify whether a “serialized form page” should be generated for the
class or package. The syntax is:
@serialinclude@serialexclude
@serialField name type descriptionA Serializable class can define its serialized format by declaring
an array of ObjectStreamField objects in a field named
serialPersistentFields. For such a class, the doc comment for
serialPersistentFields should include an @serialField tag for each
element of the array. Each tag specifies the name, type, and
description for a particular field in the serialized state of the
class.
@serialData descriptionA Serializable class can define a writeObject() method to write
data other than that written by the default serialization mechanism.
An Externalizable class defines a writeExternal() method
responsible for writing the complete state of an object to the
serialization stream. The @serialData tag should be used in the doc
comments for these writeObject() and writeExternal() methods, and
the description should document the serialization format used by
the method.
In addition to the preceding tags, javadoc also supports several
inline tags that may appear anywhere that HTML text appears in a doc
comment. Because these tags appear directly within the flow of HTML
text, they require the use of curly braces as delimiters to separate the
tagged text from the HTML text. Supported inline tags include the
following:
{@link reference }The {@link} tag is like the @see tag except that instead of
placing a link to the specified reference in a special “See Also:”
section, it inserts the link inline. An {@link} tag can appear
anywhere that HTML text appears in a doc comment. In other words, it
can appear in the initial description of the class, interface, method,
or field and in the descriptions associated with the @param,
@returns, @exception, and @deprecated tags. The reference
for the {@link} tag uses the syntax described next in
“Cross-References in Doc Comments”. For example:
@paramregexpTheregularexpressiontosearchfor.Thisstringargumentmustfollowthesyntaxrulesdescribedfor{@linkjava.util.regex.Pattern}.
{@linkplain reference }The {@linkplain} tag is just like the {@link} tag, except that
the text of the link is formatted using the normal font rather than
the code font used by the {@link} tag. This is most useful when
reference contains both a feature to link to and a label
that specifies alternate text to be displayed in the link. See
“Cross-References in Doc Comments” for more on the
feature and label portions of the reference argument.
{@inheritDoc}When a method overrides a method in a superclass or implements a
method in an interface, you can omit a doc comment, and javadoc
automatically inherits the documentation from the overridden or
implemented method. You can use the {@inheritDoc} tag to inherit the
text of individual tags. This tag also allows you to inherit and
augment the descriptive text of the comment. To inherit individual
tags, use it like this:
@paramindex{@inheritDoc}@return{@inheritDoc}
{@docRoot}This inline tag takes no parameters and is replaced with a reference to the root directory of the generated documentation. It is useful in hyperlinks that refer to an external file, such as an image or a copyright statement:
<imgsrc="{@docroot}/images/logo.gif">Thisis<ahref="{@docRoot}/legal.html">Copyrighted</a>material.
{@literal text }This inline tag displays text literally, escaping any HTML in it
and ignoring any javadoc tags it may contain. It does not retain
whitespace formatting but is useful when used within a <pre> tag.
{@code text }This tag is like the {@literal} tag, but displays the literal
text in code font. Equivalent to:
<code>{@literal<replaceable>text</replaceable>}</code>
{@value}The {@value} tag, with no arguments, is used inline in doc comments
for static final fields and is replaced with the constant value of
that field.
{@value reference }This variant of the {@value} tag includes a reference to a
static final field and is replaced with the constant value of that
field.
The @see tag and the inline tags {@link}, {@linkplain}, and
{@value} all encode a cross-reference to some other source of
documentation, typically to the documentation comment for some other
type or member.
reference can take three different forms. If it begins with a quote
character, it is taken to be the name of a book or some other printed
resource and is displayed as is. If reference begins with a <
character, it is taken to be an arbitrary HTML hyperlink that uses the
<a> tag and the hyperlink is inserted into the output documentation
as is. This form of the @see tag can insert links to other online
documents, such as a programmer’s guide or user’s manual.
If reference is not a quoted string or a hyperlink, it is expected
to have the following form:
feature[label]
In this case, javadoc outputs the text specified by label and
encodes it as a hyperlink to the specified feature. If label is
omitted (as it usually is), javadoc uses the name of the specified
feature instead.
feature can refer to a package, type, or type member, using one of
the following forms:
pkgnameA reference to the named package. For example:
@seejava.lang.reflect
pkgname.typenameA reference to a class, interface, enumerated type, or annotation type specified with its full package name. For example:
@seejava.util.List
typenameA reference to a type specified without its package name. For example:
@seeList
javadoc resolves this reference by searching the current package and
the list of imported classes for a class with this name.
typename # methodnameA reference to a named method or constructor within the specified type. For example:
@seejava.io.InputStream#reset@seeInputStream#close
If the type is specified without its package name, it is resolved as
described for typename. This syntax is ambiguous if the method is
overloaded or the class defines a field by the same name.
typename # methodname ( paramtypes )A reference to a method or constructor with the type of its parameters explicitly specified. This is useful when cross-referencing an overloaded method. For example:
@seeInputStream#read(byte[],int,int)
# methodnameA reference to a nonoverloaded method or constructor in the current class or interface or one of the containing classes, superclasses, or superinterfaces of the current class or interface. Use this concise form to refer to other methods in the same class. For example:
@see#setBackgroundColor
# methodname ( paramtypes )A reference to a method or constructor in the current class or interface or one of its superclasses or containing classes. This form works with overloaded methods because it lists the types of the method parameters explicitly. For example:
@see#setPosition(int,int)
typename # fieldnameA reference to a named field within the specified class. For example:
@seejava.io.BufferedInputStream#buf
If the type is specified without its package name, it is resolved as
described for typename.
# fieldnameA reference to a field in the current type or one of the containing classes, superclasses, or superinterfaces of the current type. For example:
@see#x
Documentation comments for classes, interfaces, methods, constructors,
and fields appear in Java source code immediately before the definitions
of the features they document. javadoc can also read and display
summary documentation for packages. Because a package is defined in a
directory, not in a single file of source code, javadoc looks for the
package documentation in a file named package.html in the directory
that contains the source code for the classes of the package.
The package.html file should contain simple HTML documentation for the
package. It can also contain @see, @link, @deprecated, and
@since tags. Because package.html is not a file of Java source code,
the documentation it contains should be HTML and should not be a Java
comment (i.e., it should not be enclosed within /** and */
characters). Finally, any @see and @link tags that appear in
package.html must use fully qualified class names.
In addition to defining a package.html file for each package, you can
also provide high-level documentation for a group of packages by
defining an overview.html file in the source tree for those packages.
When javadoc is run over that source tree, it uses overview.html as
the highest-level overview it displays.
The javadoc tool that is used to generate HTML documentation is based upon a standard API.
Since Java 9, this standard interface has been delivered in the module jdk.javadoc and tools leveraging this API are typically called doclets (with javadoc being referred to as the standard doclet).
The Java 9 release also included a major upgrade of the standard doclet.
In particular, it now (as of Java 10) generates modern HTML5 by default.
This allows for other impovements—such as implementing the WAI-ARIA standard for accessibility.
This standard makes it easier for people with visual or other impairments to access javadoc output using tools such as screen readers.
javadoc has also been enhanced to understand the new platform modules, and so the semantic meaning of what constitutes an API (and so what should be documented) is now aligned with the modular Java definition.
The standard doclet now also automatically indexes the code as documentation is generated, and creates a client-side index in JavaScript. The resulting web pages have a search capability to allow developers to easily find some common program components, such as the names of:
Modules
Packages
Types and members
Method parameter types
The developer can also add search terms or phrases using an @index inline javadoc tag.
One of the earliest slogans for Java was “write once, run anywhere.” This emphasizes that Java makes it easy to write portable programs, but it is still possible to write Java programs that do not automatically run successfully on any Java platform. The following tips help to avoid portability problems:
Portable Java code can use any methods in the core Java APIs,
including methods implemented as native methods. However, portable
code must not define its own native methods. By their very nature,
native methods must be ported to each new platform, so they directly
subvert the “write once, run anywhere” promise of Java.
Runtime.exec() methodCalling the Runtime.exec() method to spawn a process and execute an
external command on the native system is rarely allowed in portable
code. This is because the native OS command to be executed is never
guaranteed to exist or behave the same way on all platforms.
The only time it is legal to use Runtime.exec() in portable code is when the user is allowed to specify the command to run, either by typing the command at runtime or by specifying the command in a configuration file or preferences dialog box.
If the programmer wishes to control external processes, then this should be done through the enhanced ProcessHandle capability introduced in Java 9, rather than by using Runtime.exec() and parsing the output.
This is not fully portable, but at least reduces the amount of platform-specific logic necessary to control external processes.
System.getenv() methodPortable Java code must use only classes and interfaces that are a documented part of the Java platform. Most Java implementations ship with additional undocumented public classes that are part of the implementation but not part of the Java platform specification.
The modules system prevents a program from using and relying on these implementation classes, but as of Java 11 it is still possible to circumvent this protection by using reflection or runtime switches.
However, doing so is not portable because the implementation classes are not guaranteed to exist in all Java implementations or on all platforms, and they may change or disappear in future versions of the implementation that they target.
Of particular note is the sun.misc.Unsafe class, which provides
access to a number of “unsafe” methods, which can allow developers to
circumvent a number of key restrictions of the Java platform.
Developers should not make direct use of the Unsafe class under any
circumstances.
Portable code must not rely on features specific to a single implementation. For example, in the early years of Java, Microsoft distributed a version of the Java runtime system that included a number of additional methods that were not part of the Java platform as defined by the specifications. Any program that depends on such extensions is obviously not portable to other platforms.
Just as portable code must not depend on implementation-specific features, it must not depend on implementation-specific bugs. If a class or method behaves differently than the specification says it should, a portable program cannot rely on this behavior, which may be different on different platforms, and ultimately may be fixed.
Sometimes different platforms and different implementations present different behaviors, all of which are legal according to the Java specification. Portable code must not depend on any one specific behavior. For example, the Java specification does not indicate whether threads of equal priority share the CPU or if one long-running thread can starve another thread at the same priority. If an application assumes one behavior or the other, it may not run properly on all platforms.
Portable Java code never attempts to define classes in any of the system or standard extension packages. Doing so violates the protection boundaries of those packages and exposes package-visible implementation details, even in those cases where it is not forbidden by the modules system.
A portable program contains no hardcoded file or directory names.
This is because different platforms have significantly different
filesystem organizations and use different directory separator
characters. If you need to work with a file or directory, have the
user specify the filename, or at least the base directory beneath
which the file can be found. This specification can be done at
runtime, in a configuration file, or as a command-line argument to the
program. When concatenating a file or directory name to a directory
name, use the File() constructor or the File.separator constant.
Different systems use different characters or sequences of characters
as line separators. Do not hardcode \n, \r, or \r\n as the line
separator in your program. Instead, use the println() method of
PrintStream or PrintWriter, which automatically terminates a line
with the line separator appropriate for the platform, or use the value
of the line.separator system property. You can also use the “%n”
format string to printf() and format() methods of
java.util.Formatter and related classes.