Draft Java Coding Standard
written by Doug Lea and released to the public
domain.
Contents
- Structure and Documentation
- Standard ways to write and document constructions.
- Naming conventions
- Standard ways to name identifiers (class names, method names, variable names, etc).
- Recommendations
- Some rules of thumb that tend to avoid common errors and development
obstacles. You can use these guidelines to make your own design and coding
checklists to be used in retrospective code clean-up or when classes need to
be used in new contexts or placed in reusable libraries.
- Related Documents
- Links to other style guidelines etc.
The form of these guidelines is based on example coding standards and
checklists in Watts Humphrey's book A Discipline for
Software Engineering, Addison-Wesley, 1995, along with feedback from
people using previous versions of this document.
Structure and Documentation
PackagesCreate a new java package for each self-contained
project or group of related functionality. Create and use directories in accord
with java package conventions.
Consider writing an index.html file in each directory briefly
outlining the purpose and structure of the package.
Program FilesPlace each class in a separate file. This applies even to
non-public classes (which are allowed by the Java compiler to be placed in the
same file as the main class using them) except in the case of one-shot usages
where the non-public class cannot conceivably be used outside of its context.
Begin each file with a comment including:
- The file name and/or related identifying information including, if
applicable, copyright information.
- A history table listing dates, authors, and summaries of changes.
- If the file contains more than one class, list the classes, along with a
very brief description of each.
- If the file introduces a principal entry point for a
package ,
briefly describe the rationale for constructing the package.
Immediately follow each file header with:
- The
package name
- The
import list.
Example: /*
File: Example.java
Date Author Changes
Sep 1 95 Doug Lea Created
Sep 13 95 Doug Lea Added new doc conventions
*/
package demo;
import java.util.NoSuchElementException;
Classes and InterfacesWrite all /** ... **/ comments using
javadoc conventions. (Even though not required by javadoc, end each
/** comment with **/ to make it easier to read and
check.)
Preface each class with a /** ... **/ comment describing the
purpose of the class, guaranteed invariants, usage instructions, and/or usage
examples. Also include any reminders or disclaimers about required or desired
improvements. Use HTML format, with added tags:
@author author-name
@version version number of class
@see string
@see URL
@see classname#methodname
Example: /**
* A class representing a window on the screen.
* For example:
* <pre>
* Window win = new Window(parent);
* win.show();
* </pre>
*
* @see awt.BaseWindow
* @see awt.Button
* @version 1.2 31 Jan 1995
* @author Bozo the Clown
**/
class Window extends BaseWindow {
...
}
Class VariablesUse javadoc conventions to describe nature,
purpose, constraints, and usage of instances variables and static variables. Use
HTML format, with added tags:
@see string
@see URL
@see classname#methodname
Example: /**
* The current number of elements.
* must be non-negative, and less than or equal to capacity.
**/
protected int count_;
MethodsUse javadoc conventions to describe nature, purpose,
preconditions, effects, algorithmic notes, usage instructions, reminders, etc.
Use HTML format, with added tags:
@param paramName description. (Note: In alpha
versions of Java, this is listed as @arg , not
@param .)
@return description of return value
@exception exceptionName description
@see string
@see URL
@see classname#methodname
Be as precise as reasonably possible in documenting effects. Here are some
conventions and practices for semi-formal specifications.
@return condition: (condition)
- describes postconditions and effects true upon return of a method.
@exception exceptionName IF
(condition)
- indicates the conditions under which each exception can be thrown. Include
conditions under which uncommon unchecked (undeclared) exceptions can be
thrown.
@param paramname WHERE
(condition)
- indicates restrictions on argument values. Alternatively, if so
implemented, list restrictions alongside the resulting exceptions, for example
IllegalArgumentException . In particular, indicate whether
reference arguments are allowed to be null .
WHEN (condition)
- indicates that actions use guarded
waits until the condition
holds.
RELY (condition)
- describes assumptions about execution context. In particular, relying on
other actions in other threads to terminate or provide notifications.
GENERATE T
- to describe new entities (for the main example,
Threads )
constructed in the course of the method.
ATOMIC
- indicates whether actions are guaranteed to be uninterfered with by
actions in other threads (normally as implemented via
synchronized methods or blocks).
PREV(obj)
- refers to the state of an object at the onset of a method.
OUT(message)
- describes messages (including notifications such as
notifyAll ) that are sent to other objects as required aspects of
functionality, or referrred to in describing the effects of other methods.
foreach (int i in lo .. hi) predicate
- means that predicate holds for each value of i.
foreach (Object x in e) predicate
- means that the predicate holds for each element of a collection or
enumeration.
foreach (Type x) predicate
- means that the predicate holds for each instance of
Type .
-->
- means 'implies'.
unique
- means that the value is different than any other. For example, a
unique instance variable that always refers to an object that is
not referenced by any other object.
fixed
- means that the value is never changed after it is initialized.
EQUIVALENT to { code segment }
- documents convenience or specialized methods that can be defined in terms
of a few operations using other methods.
Example: /**
* Insert element at front of the sequence
*
* @param element the element to add
* @return condition:
* <PRE>
* size() == PREV(this).size()+1 &&
* at(0).equals(element) &&
* foreach (int i in 1..size()-1) at(i).equals(PREV(this).at(i-1))
* </PRE>
**/
public void addFirst(Object element);
Local declarations, statements, and expressionsUse /* ...
*/ comments to describe algorithmic details, notes, and related
documentation that spans more than a few code statements.
Example: /*
* Strategy:
* 1. Find the node
* 2. Clone it
* 3. Ask inserter to add clone
* 4. If successful, delete node
*/
Use Running // comments to clarify non-obvious code. But don't
bother adding such comments to obvious code; instead try to make code obvious!
Example: int index = -1; // -1 serves as flag meaning the index isn't valid
Or, often better: static final int INVALID= -1;
int index = INVALID;
Use any consistent set of choices for code layout, including:
- Number of spaces to indent.
- Left-brace (''
{ '') placement at end of line or beginning of
next line.
- Maximum line length.
- Spill-over indentation for breaking up long lines.
- Declare all class variables in one place (by normal convention, at the top
of the class).
Naming Conventions
- packages
lowercase . Consider using the recommended domain-based
conventions described in the Java
Language Specification, page 107 as prefixes. (For example,
EDU.oswego.cs.dl .)
- files
- The java compiler enforces the convention that file names have the same
base name as the public class they define.
- classes:
CapitalizedWithInternalWordsAlsoCapitalized
- Exception class:
ClassNameEndsWithException .
- Interface. When necessary to distinguish from similarly named classes:
InterfaceNameEndsWithIfc .
- Class. When necessary to distinguish from similarly named interfaces:
ClassNameEndsWithImpl OR
ClassNameEndsWithObject
- constants (finals):
UPPER_CASE_WITH_UNDERSCORES
- private or protected: (pick one!)
firstWordLowerCaseButInternalWordsCapitalized OR
trailingUnderscore_ , OR
thisVar (i.e. prefix with this), OR
myVar (i.e. prefix with my), OR
fVar (i.e. prefix with f)
- static private or protected:
firstWordLowerCaseButInternalWordsCapitalized OR
twoTrailingUnderscores__
- local variables:
firstWordLowerCaseButInternalWordsCapitalized OR
lower_case_with_underscores
- methods:
firstWordLowerCaseButInternalWordsCapitalized()
- factory method for objects of type X:
newX
- converter method that returns objects of type X:
toX
- method that reports an attribute x of type X:
X x() or X getX() .
- method that changes an attribute x of type X:
void x(X value) or void setX(X value) .
Recommendations
- Minimize
* forms of import . Be precise about
what you are importing. Check that all declared imports are
actually used.
- Rationale: Otherwise readers of your code will have a hard time
understanding its context and dependencies. Some people even prefer not using
import at all (thus requiring that every class reference be fully
dot-qualified), which avoids all possible ambiguity at the expense of
requiring more source code changes if package names change.
- When sensible, consider writing a
main for the principal
class in each program file. The main should provide a simple unit
test or demo.
- Rationale: Forms a basis for testing. Also provides usage examples.
- For self-standing application programs, the class with
main
should be separate from those containing normal classes.
- Rationale: Hard-wiring an application program in one of its component
class files hinders reuse.
- Consider writing template files for the most common kinds of class files
you create: Applets, library classes, application classes.
- Rationale: Simplifies conformance to coding standards.
- If you can conceive of someone else implementing a class's functionality
differently, define an interface, not an abstract class. Generally, use
abstract classes only when they are ''partially abstract''; i.e., they
implement some functionality that must be shared across all subclasses.
- Rationale: Interfaces are more flexible than abstract classes. They
support multiple inheritance and can be used as 'mixins' in otherwise
unrelated classes.
- Consider whether any class should implement
Cloneable and/or
Serializable .
- Rationale: These are ''magic'' interfaces in Java, that automatically add
possibly-needed functionality only if so requested.
- Declare a class as
final only if it is a subclass or
implementation of a class or interface declaring all of its
non-implementation-specific methods. (And similarly for final methods).
- Rationale: Making a class final means that no one ever has a chance to
reimplement functionality. Defining it instead to be a subclass of a base that
is not final means that someone at least gets a chance to subclass the base
with an alternate implementation. Which will essentially always happen in the
long run.
- Never declare instance variables as public.
- Rationale: The standard OO reasons. Making variables public gives up
control over internal class structure. Also, methods cannot assume that
variables have valid values.
- Minimize reliance on implicit initializers for instance variables (such as
the fact that reference variables are initialized to
null ).
- Rationale: Minimizes initialization errors.
- Minimize statics (except for static final constants).
- Rationale: Static variables act like globals in non-OO languages. They
make methods more context-dependent, hide possible side-effects, sometimes
present synchronized access problems. and are the source of fragile,
non-extensible constructions. Also, neither static variables nor methods are
overridable in any useful sense in subclasses.
- Generally prefer
long to int , and
double to float . But use int for
compatibility with standard Java constructs and classes (for the major
example, array indexing, and all of the things this implies, for example about
maximum sizes of arrays, etc).
- Rationale: Arithmetic overflow and underflow can be 4 billion times less
likely with longs than
ints ; similarly, fewer precision problems
occur with doubles than floats . On the other hand,
because of limitations in Java atomicity guarantees, use of longs and doubles
must be synchronized in cases where use of ints and floats sometimes would not
be.
- Use
final and/or comment conventions to indicate whether
instance variables that never have their values changed after construction are
intended to be constant (immutable) for the lifetime of the object (versus
those that just so happen not to get assigned in a class, but could in a
subclass).
- Rationale: Access to immutable instance variables generally does not
require any synchronization control, but others generally do.
- Generally prefer
protected to private .
- Rationale: Unless you have good reason for sealing-in a particular
strategy for using a variable or method, you might as well plan for change via
subclassing. On the other hand, this almost always entails more work. Basing
other code in a base class around
protected variables and methods
is harder, since you you have to either loosen or check assumptions about
their properties. (Note that in Java, protected methods are also
accessible from unrelated classes in the same package. There is hardly ever
any reason to exploit this though.)
- Avoid unnecessary instance variable access and update methods. Write
get/set -style methods only when they are intrinsic aspects of
functionality.
- Rationale: Most instance variables in most classes must maintain values
that are dependent on those of other instance variables. Allowing them to be
read or written in isolation makes it harder to ensure that consistent sets of
values are always used.
- Minimize direct internal access to instance variables inside methods. Use
protected access and update methods instead (or sometimes
public ones if they exist anyway).
- Rationale: While inconvenient and sometimes overkill, this allows you to
vary synchronization and notification policies associated with variable access
and change in the class and/or its subclasses, which is otherwise a serious
impediment to extensiblity in concurrent OO programming. (Note: The naming
conventions for instance variables serve as an annoying reminder of such
issues.)
- Avoid giving a variable the same name as one in a superclass.
- Rationale: This is usually an error. If not, explain the intent.
- Prefer declaring arrays as
Type[] arrayName rather than
Type arrayName[] .
- Rationale: The second form is just for incorrigible C prgrammers.
- Ensure that non-private
statics have sensible values even if
no instances are ever created. (Similarly ensure that static
methods can be executed sensibly.) Use static intitializers (static {
... } ) if necessary.
- Rationale: You cannot assume that non-private statics will be accessed
only after instances are constructed.
- Write methods that only do ''one thing''. In particular, separate out
methods that change object state from those that just rely upon it. For a
classic example in a
Stack , prefer having two methods
Object top() and void removeTop() versus the single
method Object pop() that does both.
- Rationale: This simplifies (sometimes, makes even possible) concurrency
control and subclass-based extensions.
- Define return types as
void unless they return results that
are not (easily) accessible otherwise. (i.e., hardly ever write ''return
this '').
- Rationale: While convenient, the resulting method cascades
(
a.meth1().meth2().meth3() ) can be the sources of synchronization
problems and other failed expectations about the states of target objects.
- Avoid overloading methods on argument type. (Overriding on arity is OK, as
in having a one-argument version versus a two-argument version). If you need
to specialize behavior according to the class of an argument, consider instead
choosing a general type for the nominal argument type (often
Object ) and using conditionals checking instanceof .
Alternatives include techniques such as double-dispatching, or often best,
reformulating methods (and/or those of their arguments) to remove dependence
on exact argument type.
- Rationale: Java method resolution is static; based on the listed types,
not the actual types of argument. This is compounded in the case of non-Object
types with coercion charts. In both cases, most programmers have not committed
the matching rules to memory. The results can be counterintuitive; thus the
source of subtle errors. For example, try to predict the output of this. Then
compile and run.
class Classifier {
String identify(Object x) { return "object"; }
String identify(Integer x) { return "integer"; }
}
class Relay {
String relay(Object obj) { return (new Classifier()).identify(obj); }
}
public class App {
public static void main(String[] args) {
Relay relayer = new Relay();
Integer i = new Integer(17);
System.out.println(relayer.relay(i));
}
}
- Declare all public methods as synchronized; or if not, describe the
assumed invocation context and/or rationale for lack of synchronization.
- Rationale: In the absence of planning out a set of concurrency control
policies, declaring methods as synchronized at least guarantees safety
(although not necessarily liveness) in concurrent contexts (every
Java program is concurrent to at least some minimal extent). With full
synchronization of all methods, the methods may lock up, but the object can
never enter in randomly inconsistent states (and thus engage in stupidly or
even dangerously wrong behaviors) due to concurrency conflicts. If you are
worried about efficiency problems due to synchronization, learn enough about
concurrent OO programming to plan out more efficient and/or less
deadlock-prone policies.
- Prefer
synchronized methods to synchronized
blocks.
- Rationale: Better encsapsulation; less prone to subclassing snags; can be
more efficient.
- If you override Object.equals, also override Object.hashCode, and
vice-versa.
- Rationale: Essentially all containers and other utilities that group or
compare objects in ways depending on equality rely on hashcodes to indicate
possible equality.
- Override
readObject and WriteObject if a
Serializable class relies on any state that could differ across
processes, including, in particular, hashCodes and transient
fields.
- Rationale: Otherwise, objects of the class will not transport properly.
- If you think that clone() may be called in a class you write, then
explicitly define it (and declare the class to
implement
Cloneable ).
- Rationale: The default shallow-copy version of
clone might
not do what you want.
- Always document the fact that a method invokes
wait
- Rationale: Clients may need to take special actions to avoid nested
monitor calls.
- Whenever reasonable, define a default (no-argument) constructor so objects
can be created via Class.newInstance().
- Rationale: This allows classes of types unknown at compile time to be
dynamically loaded and instantiated (as is done for example when loading
unknown Applets from html pages).
- Prefer
abstract methods in base classes to those with default
no-op implementations. (Also, if there is a common default implementation,
consider instead writing it as a protected method so that
subclass authors can just write a one-line implementation to call the
default.)
- Rationale: The Java compiler will force subclass authors to implement
abstract methods, avoiding problems occurring when they forget to
do so but should have.
- Use method
equals instead of operator == when
comparing objects. In particular, do not use == to compare
Strings .
- Rationale: If someone defined an
equals method to compare
objects, then they want you to use it. Otherwise, the default implementation
of Object.equals is just to use == .
- Always embed
wait statements in while loops that
re-wait if the condition being waited for does not hold.
- Rationale: When a
wait wakes up, it does not know if the
condition it is waiting for is true or not.
- Use
notifyAll instead of notify or
resume .
- Rationale: Classes that use only
notify can normally only
support at most one kind of wait condition across all methods in the class and
all possible subclasses. And unguarded suspends/resumes are even
more fragile.
- Declare a local variable only at that point in the code where you know
what its initial value should be.
- Rationale: Minimizes bad assumptions about values of variables.
- Declare and initialize a new local variable rather than reusing
(reassigning) an existing one whose value happens to no longer be used at that
program point.
- Rationale: Minimizes bad assumptions about values of variables.
- Assign
null to any reference variable that is no longer being
used. (This includes, especially, elements of arrays.)
- Rationale: Enables garbage collection.
- Avoid assignments (''
= '') inside if and
while conditions.
- Rationale: There are almost always typos. The java compiler catches cases
where ''
= '' should have been ''== '' except
when the variable is a boolean .
- Document cases where the return value of a called method is ignored.
- Rationale: These are typically errors. If it is by intention, make the
intent clear. A simple way to do this is:
int unused = obj.methodReturningInt(args);
- Ensure that there is ultimately a
catch for all
unchecked exceptions that can be dealt with.
- Rationale: Java allows you to not bother declaring or catching some common
easily-handlable exceptions, for example
java.util.NoSuchElementException . Declare and catch them anyway.
- Embed casts in conditionals. For example:
C cx = null;
if (x instanceof C) cx = (C)x;
else evasiveAction();
Rationale: This forces you to consider what to do if the object is
not an instance of the intended class rather than just generating a
ClassCastException .
- Document fragile constructions used solely for the sake of optimization.
- Rationale: See Jonathan Hardwick's
Java Optimization pages.
- Do not require 100% conformance to rules of thumb such as the ones listed
here!
- Rationale: Java allows you program in ways that do not conform to these
rules for good reason. Sometimes they provide the only reasonable ways to
implement things. And some of these rules make programs less efficient than
they might otherwise be, so are meant to be concientiously broken when
performance is an issue.
|