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
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.
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).
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.
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.
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.
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.
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.
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.
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.
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:
JavaDoc consists of the characters between /**
and */ immediately before the class, method or field
that it is commented.
The first sentence of each JavaDoc should be a summary sentence, containing a concise but complete description of the declared entity. JavaDoc copies this first sentence to the member summary at the top of the .html file.
Use HTML inline where necessary (for example, use <p> to separate paragraphs, or <pre> for code examples) but sparingly, as it tends to disrupt the readability of the source code.
Give information. Commenting the method toString()
with "returns a string representation of the object" is
not very helpful.
Write for public consumption. JavaDoc comments are there for any library users to read; write then for the general (programming) user. Avoid personal comments, and examples using 'foo' and 'bar'. Use real-world examples that are practical and relevent.
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:
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 {
...
}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 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.
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:
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;
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) 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.
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:
package name
import list.
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 should be structured as follows:
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.
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
ClassNameEndsWithException.
UPPER_CASE_WITH_UNDERSCORES
nounWithFirstWordLowerCaseButInternalWordsCapitalized.
NB – if the first word is normally all capitalised (eg FTP)
then give it all in lower case (eg ftpReader)
nounWithFirstWordLowerCaseButInternalWordsCapitalized
firstWordLowerCaseButInternalWordsCapitalized()
Briefly, properly chosen names for classes, methods and variables add significantly to readability of code or interface. Adopt the following simple rules:
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.
newX
toX
X getX().
boolean isX()void setX(X value).
public void newExample(String givenName, int[] givenPorts, URL givenAddress)
{
this.name = givenName;
this.ports = givenPorts;
this.address = givenAddress;
}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.
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.
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
Type[] arrayName rather than Type
arrayName[].
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:
Break after a comma.
Break before an operator.
Prefer higher-level breaks to lower-level breaks.
Align the new line with the beginning of the expression at the same level on the previous line.
If the above rules lead to confusing code or to code that's squished up against the right margin, just indent 8 spaces instead.
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; // AVOIDFollowing 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();
}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; }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 should follow same-level indenting, ie:
if (case1)
{
doThis();
}
else if (case2)
{
doThat();
}
else if (case3)
{
doTheOther();
}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.
import, unless using
standard libraries (eg io, swing). Be precise about what you are
importing. Check that all declared imports are actually
used.
main for the principal
class in each program file. The main should provide a
simple unit test or demo.
main
should be separate from those containing normal classes.
Cloneable
and/or Serializable.
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).
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).
private to protected
for variablesprotected to private
for methods.get/set-style methods only when they are intrinsic
aspects of functionality.
protected access and update methods
instead (or sometimes public ones if they exist
anyway).
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.
Stack, prefer
having two methods Object top() and void
removeTop() versus the single method Object pop()
that does both.
a.meth1().meth2().meth3()) can be the sources of
synchronization problems and other failed expectations about the
states of target objects.
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.
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));
}
} synchronized methods to
synchronized blocks.
readObject and WriteObject
if a Serializable class relies on any state that
could differ across processes, including, in particular, hashCodes
and transient fields.
implement
Cloneable.
clone
might not do what you want.
wait
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.)
abstract methods, avoiding problems occurring
when they forget to do so but should have.
equals instead of operator
== when comparing objects. In particular,
do not use == to compare Strings.
equals method to
compare objects, then they want you to use it. Otherwise, the
default implementation of Object.equals is just to use
==.
wait statements in while
loops that re-wait if the condition being waited for does not hold.
wait wakes up, it does not know if
the condition it is waiting for is true or not.
notifyAll instead of notify
or resume.
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.
null to any reference variable
that is no longer being used. (This includes, especially,
elements of arrays.)
='') inside if
and while conditions.
='' should have been ``==''
except when the variable is a boolean.
int unused = obj.methodReturningInt(args);
For some other standards and style guides, see
joodcs standards, with links to a Coding Standards Repository for various languages.
Coding Standards for C, C++, and Java by Vision 2000 CCS Package and Application Team
Jindent tool for automatic formatting.
How To Write Unmaintainable Code by Roedy Green.
Last modified: Wed Feb 23 18:26:38 EST 2000