This document uses the following terms to define enforcement:
Where possible these standards will be enforced by Checkstyle.
Curly braces MUST appear on a line by themselves, and align with the keyword with which they are associated.
Incorrect:
{ if (something) { variable = 0; } }
or
{ if (something) { variable = 0; } }
Correct:
{ if (something) { variable = 0; } }
We do not allow implicit blocks, this is due to subtle errors that can be introduced.
Incorrect:
{ if (something) variable = 0; }
Correct:
{ if (something) { variable = 0; } }
We require whitespace between blocks (implicit or explicit).
Incorrect:
{ if (!something) { return false; } try { doSomething(); } catch (Exception e) { log.error("Something bad happened."); } return true; }
Correct:
{ if (!something) { return false; } try { doSomething(); } catch (Exception e) { log.error("Something bad happened."); } return true; }
Note this does not mean a blank line after the last statement in an enclosing scope.
When declaring members that are collections, you should use the most generic form of the collection:
public class Foo { private Set<State> stateMap; public Foo() { stateMap = new HashSet<State>(); } }
As seen in the example above, we prefer the delaration to be absent the allocation.
NOT PREFERRED:
public class Foo { private Set<State> stateSet = new HashSet<State>(); ... }
The same is true of static members if they are non-primative types or require method invocations to initialize:
public class Foo { private static final int BUFFER_SIZE = 1024; // this is OK private static final boolean IS_UNIX; private static final Set<State> stateSet; // Statics initialized here static { stateSet = new HashSet<State>(); IS_UNIX = (getOs().indexOf("nix") > 0 ? true : false); } }
NOTE: it is acceptable to use a single-line declaration/initializer in the case of a Log4j logger:
private static final Logger DEV_LOG = Logger.getLogger(Foo.class);
The use of Vector, Hashtable are forbidden. These are internally synchronized collections with a locking granularity that is inappropriate for use within a server. Similarly, Stack (a subclass of Vector) is also forbidden, instead use a LinkedList (using the addLast() and removeLast() methods).
Know your collection classes! Java5 adds a new package java.util.concurrent. Spend an hour and literally read all of the JavaDoc for these classes, they are designed for use in products like servers. In particular, in a multi-threadeded context there is no reason to use and synchronize on a HashMap instance; instead, use ConcurrentHashMap. This is an extremely high-performance thread-safe Map implementation that is synchronization-free in all but a few cases.
Lastly, you MUST use the interface associated with a collection when declaring members, parameters. Preferred is the use of the generic interface for local variables. For example, even if the implementation of a collection is ArrayList, declare the variable to be of type List. Similarly so with Map, Set, and Queue. The only exception is if you can demonstrate that knowledge of the collection type is critical to understanding the code or accessing methods only available on the specific collection class.
All classes, and methods (regardless of scope), MUST include JavaDoc. JavaDoc comments for methods MUST include @param and @return markup if applicable. Member variables are optional.
The hard line-length limit on comments is 160 characters, however, try to keep JavaDoc comment lines below 120.
For JavaDoc styles, please refer to http://java.sun.com/j2se/javadoc/writingdoccomments/#styleguide
If you overload the equals() method, you MUST overload the hashCode() method.
Additionally, we prefer the following pattern for equals:
public boolean equals(Object obj) { if (obj == null) { return false; } else if (this == obj) { return true; } try { Foo f = (Foo) obj; return this.value == f.value; } catch (ClassCastException cce) { return false; } }
This pattern has shown to be extremely performant in the nominal case in which a 'Foo' object is passed into the above method. It avoids explicit checks for class equivalency and in the 'failure' case performs as well as 'instanceof' based implementations on most JVMs.
'Covariant' equals() implementations are strongly discouraged. A covariant equals() method is an equals method declared to take an object of a specific type (rather than Object). Covariant equals have been shown to introduce subtle bugs. The 'pain' of casting, as above, is fairly light.
Code MUST appear in the following order in a class:
Members MUST appear in this order:
An anonymous static block runs when the class is loaded and can be used to initialize static members (including static final members!). It MUST appear after the members, but before the constructors.
Constructors MUST appear in this order:
In accordance with the Java Language specification, sections 8.1.1, 8.3.1, and 8.4.3 the preferred order for method modifiers is: public, protected, private, abstract, static, final, transient, volatile, synchronized, native, strictfp
Methods MUST appear in this order:
There is no ordering currently imposed within a given scope block. So, for example, public methods need not be in alphabetical order.
Additionally required is a 'separation banner' between each, for example:
// ------------------------------------------------------------------------------ // P U B L I C M E T H O D S // ------------------------------------------------------------------------------
Java5 enums are in reality a class, and implicitly extend java.lang.Enum just as classes extend java.lang.Class. Public enums should be defined in a separate file. Private enums should appear in the inner class section mentioned below.
Preferred is this format:
private enum State { PARSING, GENERATING, COMPILING, COMPLETE }
Rather than this format:
private enum State {PARSING, GENERATING, COMPILING, COMPLETE}
Enums can do all kinds of CrAZy things in Java5 – they can implement interfaces, extend other enums, contain methods, implement value-specific class bodies (!), and can be generic.
Currently, we discourage ALL of these possibilities with these exceptions:
Any use of the other capabilities will have to be lobbied for heavily in a code review.
Inner classes must appear in the following order:
Currently, public and package scoped inner classes would have to be lobbied for in a code review, but generally speaking they are not allowed.
Inner classes that exceed 200 lines should be considered for a package-scoped first-order class, even if it is only utilized by the containing class.
Inner classes that access no containing class members should be considered for a package-scoped first-order class.
Static inner class? What are you smoking? Lobby for it in a code review.
Required is a 'separation banner' above the first inner class, for example:
// ------------------------------------------------------------------------------ // I N N E R C L A S S E S // ------------------------------------------------------------------------------
This example class employs most of the above semantics (it does not contain JavaDoc for brevity):
public class Demonstration { // -- Statics public static final String EXTERNAL_CONSTANT = "External Constant"; protected static final Map STATE_MAP; private static final int BUFFER_SIZE = 1024; // -- Members protected BlockingQueue queue; private State currentState; private int maxValue; // -- Static initializer static { if (Boolean.getProperty("ThreadSafe")) { STATE_MAP = new ConcurrentHashMap(); } else { STATE_MAP = new HashMap(); } } // ---------------------------------------------------------------- // C O N S T R U C T O R S // ---------------------------------------------------------------- public Demonstration(int size) { queue = new LinkedBlockingQueue(size); currentState = State.INITIAL; } private Demonstration() { // there is no public default constructor. } // ---------------------------------------------------------------- // P U B L I C M E T H O D S // ---------------------------------------------------------------- public static int getMapSize() { return STATE_MAP.size(); } public int getMaxValue() { return maxValue; } public void setMaxValue(int value) { maxValue = value; } // ---------------------------------------------------------------- // P R O T E C T E D M E T H O D S // ---------------------------------------------------------------- protected void enqueue(Object obj) { queue.offer(obj); } protected State getCurrentState() { return currentState; } // ---------------------------------------------------------------- // P R I V A T E M E T H O D S // ---------------------------------------------------------------- private void resetState() { currentState = State.INITIAL; } // ---------------------------------------------------------------- // I N N E R C L A S S E S // ---------------------------------------------------------------- protected enum State { INITIAL, PARSING, BUILDING, COMPLETE, } private class Parser implements Runnable { public void run() { // run method } } }