Main.ZipTie Coding Standard
This document uses the following terms to define enforcement:
MUST - this convention is a requirement
require - same as MUST
should - this convention is a strong suggestion
prefer - same as should
Where possible these standards will be enforced by Checkstyle.
Braces
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;
}
}
Blocks
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;
}
}
Whitespace
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.
Declarations
When declaring members that are collections, you
should use the most generic form of the collection:
public class Foo
{
private Map<State> stateMap;
public Foo()
{
stateMap = new HashMap<State>();
}
}
As seen in the example above, we
prefer the delaration to be absent the allocation.
NOT PREFERRED:
public class Foo
{
private Map<State> stateMap = new HashMap<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 Map<State> stateMap;
// Statics initialized here
static
{
stateMap = new HashMap<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);
Collections
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. In fact, given the introduction of the Lock interface and it's implementers there is no reason to ever use the
synchronized keyword.
Lastly, you
MUST use the
interface associated with a collection when declaring members, parameters, and 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.
JavaDoc
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
Overloading equals()
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 Organization
Code
MUST appear in the following order in a class:
Members
Members
must appear in this order:
- public statics
- protected statics
- package statics
- private statics
- <blank line>
- public members
- protected members
- package members
- private members
Static Blocks
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
Constructors
must appear in this order:
- public constructors
- protected constructors
- package constructors
- private constructors
Methods
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:
- public methods (static and instance)
- protected methods (static and instance)
- package methods (static and instance)
- private methods (static and instance)
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
// ------------------------------------------------------------------------------
Enums
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:
- An enum may implement Serializable, and contain a SerialVersionUID
- An enum may implement toString() in such as way as to provide meaningful string representations
- An enum may override any of the methods in java.lang.Enum. These include, but are not limited to, equals(), hashCode(), name(), and ordinal().
Any use of the other capabilities will have to be lobbied for heavily in a code review.
Inner Classes
Inner classes
must appear in the following order:
- protected inner classes
- private inner classes
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
// ------------------------------------------------------------------------------
Example
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
}
}
}
--
BrettWooldridge - 30 Jan 2007