JavaPLT coding conventions

Originally written 6/18/2001 by Brian Stoler, as adapted from past experience at Oracle and elsewhere. Updated 1/22/2003 by Eric Allen and 1/14/2005, 1/9/2007 by Corky Cartwright.

Our conventions follow the Sun Java coding conventions (http://java.sun.com/docs/codeconv/html/CodeConvTOC.doc.html). with the following exceptions and clarifications:

Packages

Java classes should be packaged as a subpackage of edu.rice.cs, to prevent name clashes. Each major project should have one top-level package under edu.rice.cs, and then large subcomponents of each should form subpackages under each. Current package names:

When we incorporated DynamicJava as part of our code base, we retained its package names. We may move it into the edu.rice.cs package hierarchy at a later date.

Subversion

All source should be maintained in Subversion (svn) using our ant scripts which force code to compile and pass all unit tests before it can be checked into the Subversion database. Remember to perform svn add operations for every file that you add to the database.

README

All packages should have a text file named README describing, at least, the purpose of the package.

Class layout

The elements of a class should be laid out in the following order:
  1. Constants (i.e., static final fields).
  2. Static fields.
  3. All other fields that do not contain instances of anonymous inner classes.
  4. Fields containing instances of anonymous inner classes.
  5. Public static methods and constructors.
  6. Public methods.
  7. Protected methods
  8. Private and package private methods. Due to our use of JUnit, it is often necessary to increase method visibility from private to package private, so we tend to use the two interchangeably.

Documentation

Every public or protected method should have an associated javadoc comment. Inside a method, use extra comments to explain unusual behavior, or behavior that relies on non-local state (i.e., state outside of the method). Write comments to explain why your code does what it does, rather than simply rewriting the code in English.

Indentation

Indentation is two space characters. Tab characters should NEVER be used. This ensures that source files will look right no matter which editor someone uses. Similarly, lines should never span more than 120 characters. We used to enforce an 80 character limit, but with increasing screen sizes this limit seemed anachronistic. Lines should fit on a machine running DrJava in the full screen of a 1024x768 display. Most lines should be short and indentation levels should be modest.

Braces

The opening brace goes at the end of the first line of a new block, as opposed to the beginning of the subsequent line. The only exceptions are when the opening of the block spans more than one line, e.g., a class that implements more interfaces that can fit on one line, or when a method has a very long signature.

Conditional and loop bodies should always use braces, unless the body can fit on the same line as the header.

Also, else, if/else and catch/finally should begin on their own line.

Example conditional:

    if (test) {
      ...
    }
    else if (test2) {
      ...
    }
    else {
      ...
    }
    

Example try/catch/finally:

    try {
      ...
    }
    catch (Exception e) {
      ...
    }
    finally {
      ...
    }
    

If a catch or finally body fits on one line, the enclosing braces may be placed on the same line.

Mutation in expressions

Unless it is unavoidable (which it usually is not) or would terribly reduce code readability, do not change any state in an expression. This includes conditional or loop test expressions. All mutations should be written as their own statements. If you change state in an expression, explain what's going on and why in comments. For example:

      l = l.rest();
      f = l.first();
    
is preferable to:
     f = l.pop().first();
   

Variable naming conventions

Ternary (?) operator

Expressions using the ternary operator should be avoided unless they are very succinct. In most cases, they are confusing, and furthermore in Java it does not generate any better code than the corresponding if statement.

JUnit: Don't use the assert() method!

Since Java 1.4, assert has been a keyword. Thus, compiling code that uses this function (as was previously used in JUnit) will fail. Thus, JUnit renamed its functions to assertTrue().

Never catch and do nothing!

As a matter of principle, never leave a catch clause empty. It's irrelevant whether you can prove that the catch clause is unreachable. Your proof will undoubtably rely on the correctness of the rest of the code (including the code in the try clause), which is never a given. If you are nonetheless certain that the clause will never be reached, throw an UnexpectedException in it. The UnexpectedException class is defined in the package edu.rice.cs.util; it should have been included by the Java designers in java.lang. Do not throw a RuntimeException; in constrast to an UnexpectedException, it does not propogate the underlying exception that was caught. Even if this helps to catch only one bug in a hundred, the time it takes will more than pay for itself.

The only exception to this rule is a test case that specifically checks that an exception is properly thrown. In all other test cases, it is a mortal sin to catch an exception and do nothing. In general, test cases should not include try-catch blocks. Instead, they should simply throw exceptions to the caller.