Java Coding Standard

This is from AstroGrid's initial Java Coding Standard, based on Dog Lea's excellent sample

v1, Doug Lea
v2, Oct 2002, M C Hill & K Andrews (AstroGrid)
v3, Oct 2005, M C Hill

Contents

In General
'Good' approaches to coding
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.
Related Documents
Links to other style guidelines etc.

In General

Being able to understand code is especially important in an object-oriented language such as Java, where code should be reused and inherited wherever possible. Note that some of these points can conflict with those that make your code faster or smaller.

Use good tools

The less time you spend worrying about editing, compiling, storing, and viewing code, the more time you can spend getting it right. There are many commercial IDEs available (often with freely-available trial versions), as well as a bunch of free ones, plus assorted tools such as code repositories, class browsers, code decompilers, etc. There are also many reviews online (e.g. from JavaWorld, or Dave Dyer).

No fancy tricks

Write code to be read by a human, not by a compiler. Don't use any other optimizations that make your code harder to read or understand.

No assumptions

Write for the junior programmer. For example, parenthesize expressions rather than assuming that everyone knows the operator precedence rules. Similarly, don't rely on implicit superclass constructor calls or default constructors without using comments to make their absence explicit.

Document the code

Use javadoc to produce online documentation for your classes. This is easier to keep synchronised than separate document files. Consider including an index.html in the package directory to describe the package.

Avoid gray areas

Certain areas of the Java spec can be unclear or buggy. Try to avoid code that depends on a particular interpretation of the spec, or that depends on a buggy implementation. See also the Java Hall of Shame.

Avoid optimising

The simple rule is “don't do it”, and for experts “don't do it yet”. Leave major effort on optimising code to bottlenecks that are identified using optimisation tools once the application has been assembled. Having said that, there are some general principles that make little difference to code and can avoid introducing performance problems – see the Optimisation section below.

Don't Abbreviate

Particularly in comments, use the full description unless the abbreviation is really well known within the context. For example, given the web service context, abbreviations such as SOAP and WSDL might be acceptable, but IDL (Interface Definition Language, or Interactive Data Language) is not.

Similarly, avoid shortening words in methods or field names, such as 'Received' to 'recvd', 'rcv', etc. It makes libraries more difficult to understand, and library users have to memorise the particular shortening be used when calling those methods.

Apps Hungarian Notation

Where you have similar variables that are differentiated by purpose it can be useful to use what Joel (On Software) calls Apps Hungarian. This is a variable name prefix based on the 'purpose' (not type) of the variable, where you have other similar ones. So you might use 'dc' as a database cursor, ie dcCustomer and dcInvoice, rather than making longer variable names.

Comments on Comments & JavaDoc

If comments are well thought out, one should be able to extract good process and use-documentation from the source code alone. JavaDoc provides a mechanism for doing this automatically. See also javadoc and How to Write Doc comments for the JavaDoc tool:

Classes and Interfaces

Class functionality should be clearly outlined up front, so no one is forced to browse through pages and pages of source code to find out functionality. Immediately before each class, include a JavaDoc comment giving:

  1. A description of the class, including:
    1. purpose
    2. guaranteed invariantes
    3. usage instructions, preferably with examples
    4. reminders about required/desired improvements, existing problems, etc
  2. The last change date and author. If the change is minor, include the original author.
  3. If the file introduces a principal entry point for a package, briefly describe the rationale for constructing the package.

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 Variables

When public or protected, use javadoc conventions to describe the nature, purpose, constraints, and use of static variables.

Example:

    /**
     * The current number of elements.
     * must be non-negative, and less than or equal to capacity.
     **/
    protected int count;

Instance Variables

Instance variables will generally be private (think very carefully before exposing any publically) and so javadoc comments may be unnecessary. For readability you may want to use single line comments, but do not forget to document them if necessary just because they take up so little space.

Methods

Method comments may be in two parts - JavaDoc describing how the method is used by the caller, and an implementation comment.

Implementation comments can be given inside the curley brackets and below the variable declarations, so that the reader already has the signature (what is it?) when reading the implementation comment (how is it done?) . Ideally, most of the methods should be short, and therefore all the implementation comments may be in this one place only.

Marry your comment to the method; if a method returns:

boolean Start with "Is....?", or "True if ...", or "False if ..."
void Start with imperative sentence, such as: "Connect to Internet Provider.."
other type Start with a noun, or adjective + noun, describing the object being returned. For example: "New string with all capital letters", or "Server port name". Bean-like accessors (getXxxx()) might prepend the word 'Returns' or 'Get'

Implementation Comments

By using // comments to clarify non-obvious code, it is easier to comment out blocks of code using /*. . . */.

Don't add 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;

Verbose Text

Well written comments should convey information in a clear, precise and terse manner. An example from JDK String class:

        /**
        * Compares this String to the specified object.
        * Returns true if the object is equal to this String; that is,
        * has the same length and the same characters in the same sequence.
        * @param anObject       the object to compare this String against
        * @return       true if the Strings are equal; false otherwise.
        */
        public boolean equals(Object anObject) 

can be said much more simply:

        /**
         * True if 'anObject' is equal to this string; that is,
         *  has the same length and the same characters in the same sequence.
         */
        public boolean equals (Object anObject) 

Structure

Packages

Create 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 Files

Place 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.

While most modern IDEs will print the classname as a header, not everyone will be using an IDE to print code, and so each file should begin with an ordinary (non-JavaDoc) comment including:

Immediately follow each file header with:

Then with the class comments and definitions.

Example:

/*
   File: ExampleDoc.java

   Date      Author      Changes
   Sep 1  02 M Hill      Created  
   Sep 13 02 K Andrews   Major changes to fix exception in getBackground()

   (c) Copyright Astrogrid 2002; all rights reserved.
   See http://www.astrogrid.org/code_licence.html for terms of usage.
*/

package demo;
import java.util.NoSuchElementException;

/** 
 * ExampleDoc is a non-existant class used to 
 * demonstrate how to write and lay out a class definition
 * file
 * @version %I%
 * @author M Hill
 * @author K Andrews
 * @see http://java.sun.com/javadoc 
 */

public ExampleDoc
{
  ...
}

Classes and Interfaces

Classes and Interfaces should be structured as follows:

  1. javadoc
  2. class/interface statement
  3. Implentation comment (if necessary)
  4. class (static) variables: public, protected, package then private
  5. instance variables: public, protected, package then private (although it is better to group by functionality rather than accessiblity when different.)
  6. constructors:
  7. methods: Grouped by functionality.

Naming Conventions

Packages

lowercase. Use the recommended domain-based conventions described in the Java Language Specification, page 107 as prefixes. In the case of Astrogrid, this is org.astrogrid.

Files, Classes and Interfaces

NounCapitalizedWithInternalWordsAlsoCapitalized. The java compiler enforces the convention that file names have the same base name as the public class they define. NB – if the first word is normally all capitalised (eg FTP) then give it in lower case with leading letter capitaled (eg FtpReader). Try and avoid similar names between interfaces and classes; if this is difficult, InterfaceNameEndsWithIfc and ClassNameEndsWithImpl

Exception classes

ClassNameEndsWithException.

Constants (finals)

UPPER_CASE_WITH_UNDERSCORES

Class or instance variables

nounWithFirstWordLowerCaseButInternalWordsCapitalized. NB – if the first word is normally all capitalised (eg FTP) then give it all in lower case (eg ftpReader)

Local variables

nounWithFirstWordLowerCaseButInternalWordsCapitalized

Methods

firstWordLowerCaseButInternalWordsCapitalized()

Briefly, properly chosen names for classes, methods and variables add significantly to readability of code or interface. Adopt the following simple rules:

Verb in imperative for void procedures
Verb can have a noun as complement, as in compareAccounts, or can be qualified by an adverb or adjective, as in deepCopy
Noun for functions or variables denoting some objects
Noun may be qualified by an adjective or another noun, as in decayRate, or firstItem
Adjective or prefix is for boolean query
If there is no adjective available that would suggest a true or false property, such as greedy, then use the prefix is, as in isOnLine. Some English words can be an adjective or verb (as in empty) - when in doubt, qualify with is.

Unfortunately the bean-standard encourages the verb 'get' for functions or variables denoting some objects, so that in the example above we end up with getDecayRate. Use the bean standard only when defining bean properties.

Factory method for objects of type X:

newX

Converter method that returns objects of type X:

toX

Bean-like method that reports an attribute x of type X:

X getX().
Or for boolean values:
boolean isX()

Bean-like method that changes an attribute x of type X:

void setX(X value).

Method arguments/parameters

Where separate descriptive names are difficult, use 'given' as argument prefixes to distinguish from other local variables, and use 'this' to explicitly reference similarly named instance variables, eg:
public void newExample(String givenName, int[] givenPorts, URL givenAddress)
{
    this.name = givenName;
    this.ports = givenPorts;
    this.address = givenAddress;
}

Formatting

As many tools automatically provide templates and formatting shortcuts (such as automatic indentation) it makes sense to standardise code formats so that any particular piece of code is similar to any other, making it easier to read and check for syntax errors.

Blocks & Indentation

Curley brackets should match on the same lines - that is a an opening bracket should be on its own line, with the closing bracket at the same indentation. All code between should be indented an extra 4 spaces. Indentations should be by spaces not tabs.

Always always bracket statements following for, if or while statements.

Declarations

One per line, initialised where they're declared, and at the beginning of the blocks they are used. For example:

int     level = 0;      // indentation level
int     size = 10;      // initial size of table  
Object  currentEntry     // currently selected table entry
Use Type[] arrayName rather than Type arrayName[].

Line length & Wrapping

Lines should not exceed 80 characters, except in unusual circumstances where several lines can be more neatly laid out (and compared) when not wrapped.

When an expression will not fit on a single line, break it according to these general principles:

Here are some examples of breaking method calls:

someMethod(longExpression1, longExpression2, longExpression3,
        longExpression4, longExpression5);

var = someMethod1(longExpression1,
                 someMethod2(longExpression2,
                 longExpression3));

Following are two examples of breaking an arithmetic expression. The first is preferred, since the break occurs outside the parenthesized expression, which is at a higher level:

longName1 = longName2 * (longName3 + longName4 - longName5)
            + 4 * longname6; // PREFER

longName1 = longName2 * (longName3 + longName4
                       - longName5) + 4 * longname6; // AVOID

Following are two examples of indenting method declarations. The first is the conventional case. The second would shift the second and third lines to the far right if it used conventional indentation, so instead it indents only 8 spaces.

//CONVENTIONAL INDENTATION
someMethod(int anArg, Object anotherArg, String yetAnotherArg,
           Object andStillAnother) 
{
   ...
}

//ALTERNATIVE 
someMethod(int     anArg,
           Object  anotherArg,
           String  yetAnotherArg,
           Object  andStillAnother)
{
   ...
}

//INDENT 8 SPACES TO AVOID VERY DEEP INDENTS
private static synchronized horkingLongMethodName(
        int anArg, Object anotherArg, String yetAnotherArg,
        Object andStillAnother) 
{
   ...
}

Line wrapping for if statements should generally use the 8-space rule, since conventional (4 space) indentation makes seeing the body difficult. For example:

//DON'T USE THIS INDENTATION
if ((condition1 && condition2)
    || (condition3 && condition4)
    ||!(condition5 && condition6)) { //BAD WRAPS
    doSomethingAboutIt();            //MAKE THIS LINE EASY TO MISS
}

//USE THIS INDENTATION INSTEAD
if ((condition1 && condition2)
        || (condition3 && condition4)
        ||!(condition5 && condition6)) 
{
    doSomethingAboutIt();
}

//OR USE THIS
if ((condition1 && condition2) || (condition3 && condition4)
         ||!(condition5 && condition6)) 
{
    doSomethingAboutIt();
}

Bean Property getters & setters

Some property getter/setters are provided only to give bean manipulators a handle on the properties, and may be extremely simple. Where many of these occur, a condensed method may be used, for example:

public void  setBackground(Color aBackground) { this.background = aBackground; }

public Color getBackround()                   { return background; }

Switch Statements

A switch statement should have the following form:

switch (condition) 
{
    case ABC:
        statements;
        /* falls through */

    case DEF:
        statements;
        break;

    case XYZ:
        statements;
        break;

    default:
        statements;
        break;
}

Every time a case falls through (doesn't include a break statement), add a comment where the break statement would normally be. This is shown in the preceding code example with the /* falls through */ comment.

Every switch statement should include a default case. The break in the default case is redundant, but it prevents a fall-through error if later another case is added.

If-else-if Statements

If -else – if statements should follow same-level indenting, ie:

if (case1)
{
    doThis();
}
else if (case2)
{
    doThat();
}
else if (case3)
{
    doTheOther();
}

Optimising

The big performance hit wth Java is the garbage collector. To reduce its impact, reduce the load on it by reducing the number of objects being created or removed.

One way of doing this is to use a 'pool' of objects, and instead of creating new ones, re-use those from the pool. This does however require extra code, introduces posisble bugs, and generally re-introduces the spectre of double-pointers (where references to the same object believe they are references to different objects) that java has so nicely removed.

All the same, designs should be avoided that create and dispose of large numbers of small objects. One area where this can be missed is in string processing. Because strings are immutable, the following bit of (daft) code creates a vast number of string instances that are left on the heap to be collected:

String s = “”;
for (int i=0;i++;i<1000)
{
    s=s + “”+i;
}

Each iteration of the loop creates a new string. In such situations it is better to use StringBuffer, or byte arrays.

Recommendations

Minimize * forms of import, unless using standard libraries (eg io, swing). 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.
Avoid using 'tenery' expressions, eg alpha = (delta) ? beta : gamma;
Rationale: It is not as self-documenting as if statements
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.
Always explicitly initialise instance variables.
Rationale: Minimizes initialization errors due to assumptions
Avoid 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.
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 private to protected for variables
Rationale: Exposing variables even to subclasses means we cannot definitely count on their validity. Exposing internal variables only via methods means we can ensure the values are always valid and dependencies always updated. changed MCH 3/Oct
Generally prefer protected to private for methods.
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
Avoid unnecessary instance variable accessors. 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.
Avoid 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.
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.
Avoid the return type '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); 
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.

Related Documents

For some other standards and style guides, see


Doug Lea

Last modified: Wed Feb 23 18:26:38 EST 2000