Vanderbilt Component Engineering Group

Java Coding Standard

Version 1.0

This coding standard is based on Doug Lea's Draft Java Coding Standard. Component Engineering Group developers customized Doug Lea's standard to apply at Vanderbilt and accomodate our group's needs. In addition, segments of this document were copied from Sun's Java Code Conventions.

This standard will be used as the basis for Java code reviews. It is expected that this document will evolve as the group's experience provides new best practices.

Adapted with permission from CODE CONVENTIONS FOR THE JAVATM PROGRAMMING LANGUAGE. Copyright 1995-1999 Sun Microsystems, Inc. All rights reserved.

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. These are recommendations rather than strict requirements, but developers should have valid justification for contradicting them.
Related Documents
Links to other style guidelines etc.

The form of Doug Lea's 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 Doug Lea's document.

Structure and Documentation

Code documentation described below should be in Javadoc format to allow automatic production of Javadoc output as part of the build process. The goal of this documentation is to provide enough information to enable other developers to understand and use your classes without reading your source code. For more information on Javadoc, see the Javadoc home page.

Packages

Before creating a new package, determine if there is an existing package for the functionality of interest. Although the Component Engineering Group's build process currently does not create Javadoc documents for the entire archive, documentation for many of Vanderbilt's packages can be found here: Vanderbilt Javadoc. For projects not represented in these documents, talk to the responsible developers.

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. The group's current Java packages deviate from convention by starting with "vanderbilt." rather than "edu.vanderbilt.". Rather than renaming all existing packages, the group will continue to start its package names with "vanderbilt.".

Write a package.html file in each directory briefly outlining the purpose and structure of the package. Javadoc will incorporate this file into the package's documentation, and developers can use this information to decide where new classes belong. The first sentence in the package.html file should be a summary starting with a verb, like the following statement from Sun's java.io package:

	Provides for system input and output through data streams, serialization and the file system.
	
An empty template file for package.html files can be found here (view the HTML source): package template.

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. If a class is only used by one other class (e.g. inner classes used for GUI programming), it may be placed in the same file as its client class.

Each file should contain the following sections is the following order:

  1. A file header containing the file name, history table listing dates, authors, and summaries of changes, etc. See File Header Template for the template.
  2. The package name.
  3. The import list.
  4. Class/interface Javadoc header. See Class Header Template for the template.
  5. Class/interface implementation comment, if necessary. This comment should contain any class-wide or interface-wide information that wasn't appropriate for the class/interface Javadoc header.
  6. Class (static) variables. First public, then protected, then package, then private variables.
  7. Instance variables. First public, then protected, then package, then private variables.
  8. Constructors.
  9. Methods. These should be grouped by functionality rather than by scope or accessibility. For example, a private class method can be in between two public instance methods. The goal is to make reading and understanding the code easier.

File Header Template

// File:         [File name]
// Created:      [yyyy/mm/dd creation date]
// Last Changed: $Date: 2000/08/09 15:15:25 $
// Author:       <A HREF="mailto:[Email address]">[Name]</A>
//
// This code is copyright (c) 2000 Vanderbilt University Medical Center
// 
// History:
//  $Log: javaCodingStd.html,v $
//  Revision 1.1.1.1  2000/08/09 15:15:25  adamkmy
//  initial impound
//
   

Classes and Interfaces

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

Class Header Template

/**
   [Class description.  The first sentence should be a meaningful summary of the class since it
   will be displayed as the class summary on the Javadoc package page.]
   
   [Other notes, including guaranteed invariants, usage instructions and/or examples, reminders
   about desired improvements, etc.]
   
   @author <A HREF="mailto:[Email address]">[Name]</A>
   @version $Revision: 1.1.1.1 $ $Date: 2000/08/09 15:15:25 $
   @see [String]
   @see [URL]
   @see [Class name#method name]
**/
   
In addition to the class header, each class should contain the following string constant. This constant identifies the version of the class using PVCS keywords. This allows easy determination of the version level of classes deployed in a Jar file or as stand-alone classes.
   /** Embedded PVCS revision string **/
   public static final String REVISION = "$Revision: 1.1.1.1 $";
   

Class and Instance Variables

Use javadoc conventions to describe the nature, purpose, constraints, and usage of static variables and instance variables. Every variable should be documented. In addition, constants should be cleary documented, including the rationale for the value of the constant. Use HTML format, with added tags:

Example:

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

Methods

Use javadoc conventions to describe the nature, purpose, preconditions, effects, algorithmic notes, usage instructions, reminders, etc. All non-private methods should be documented, and private methods should also be documented unless they are very simple. This documentation should provide enough information for a client to use the methods of a class without looking at the class's implementation. Note that the Javadoc tool allows control over the level of documentation produced (public only, protected, or private access).

Use the following template for method documentation:

/**
  [Sentence summarizing the method's purpose and functionality.]
  [Other comments describing preconditions, postconditions, algorithm notes,
  usage instructions, reminders, etc.]
  
  @return [Description of return value]
  @exception [Name of exception class and description of the scenario]
  @see [String]
  @see [URL]
  @see [class name#method name]
**/
   

Be as precise as reasonably possible in documenting effects. Below are some suggested conventions for semi-formal specifications. Note that it is not required to use these constructs in documenting every method; use them where they are helpful in clearly specifying a method's semantics.

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

Local declarations, statements, and expressions

Use /* ... */ 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;

Code Layout

Individual developers are free to choose from the widely accepted options for code layout, as long as these options are applied consistently. Every source file should be internally consistent. If a developer modifies a source file that follows another convention, the developer should maintain consistency with the existing code in the file. Alternatively, if a developer assumes primary responsibility for a source file, he may modify the entire file to follow his typical code layout convention. Acceptable choices include 1 choice in each of the following areas:

Naming Conventions

packages
lowercase.
All package names should start with "vanderbilt."
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
constants (finals):
UPPER_CASE_WITH_UNDERSCORES
private or protected:
myVar (i.e. prefix with my)
static private or protected:
ourVar
local variables:
firstWordLowerCaseButInternalWordsCapitalized
methods:
firstWordLowerCaseButInternalWordsCapitalized()
method parameters:
inParam, outParam, or inOutParam. If the method reads the parameter but does not modify its contents, prefix the parameter with in. If the method receives an empty parameter and sets its contents as a return value, prefix the parameter with out. If the method reads the contents of a parameter and modifies them, prefix the parameter with inOut.
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 getX()
method that changes an attribute x of type X:
void setX(X value)

Recommendations

Files longer than 2000 lines are cumbersome and should be avoided.
Rationale: File this long usually indicate that a developer has not properly decomposed the design into classes that each have a well defined interface and set of responsibilities.

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 int to long, and float to double.
Rationale: 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. Keep in mind, however, the potential for arithmetic overflow and underflow when using ints rather than longs; similarly, precision problems are more likely with floats than doubles. In most of our code, synchronization problems are more likely than precision or overflow problems.

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.

Related Documents

For some other standards and style guides, see