Thomas A. Alspaugh
Java Coding Standards

In general

There are two ways of constructing a software design. One way is to make it so simple that there are obviously no deficiencies. And the other way is to make it so complicated that there are no obvious deficiencies.

C.A.R. Hoare

Program code is read by two audiences: people, and compilers. Both must be satisfied. Write your code so that there are obviously no deficiencies. Complicated code always has deficiencies, they're just harder to find and harder to fix.

Right is more important than fast

First get it right, then maybe get it efficient.

Only make it efficient if efficiency is needed for that part of the code. But always make it right. Correctness is always needed for every part of your code. It is often the case that early effort spent making code efficient gets in the way of making it right, and frequently is thrown away anyway when the specification changes.

It is never appropriate to make it fast before making it right. After all, it's easy to write software that does the wrong thing quickly (if you are in a real hurry, just use the class below).

  public class FastButWrong {
    public FastButWrong() {  throw new RuntimeException();  }
  }

Align your code with what it does

  1. The name of something should give the thing's meaning. Don't use short or cryptic or abbreviated variable names, except in the very few situations that are so hallowed by long usage that they are more clear than a long name. The ones I find acceptable are:
    1. cc for the character (but there must be just one character that your program deals with at a time for this to be effective),
    2. j and k for integer indexes (but there must be just one or two possible things being indexed), and
    3. pv, cu, and nx for the previous, current, and next one (but there must be just one kind of thing that your program deals with in that region of your code).
  2. Do rename your variables, methods, etc. if what they mean has changed — don't keep an old name just because it's tedious to change it.
  3. More shorter methods are almost always better than fewer longer methods. Keep them simple. Choose your methods to be simple enough that each one's implementation can be obviously correct.
  4. Write your code so that it presents the steps it performs in the order in which a person would naturally think about them.
  5. It is often easier to implement a solution to a more general problem, than a solution to a smaller and more specific problem. The more specific problem can then be solved by the general solution.
  6. Use appropriate design patterns; they save you trouble and make your code clearer, because you are reusing the thinking that other people have done, and that your readers might already understand.
  7. In the very common case where the attributes of the class are the parameters of the constructor, use the same names for each, but with initial underscores for the parameters. Then mistakes are obvious.
      Formula left;
      Formula right;
      /**
        Constructs the disjunction of two subformulas.
        @param _left  The first  subformula.
        @param _right The second subformula.
      */
      public Disjunction(Formula _left, Formula _right) {
        left  = _left;
        right = _right;
      }
    

Javadoc comments

  1. Write javadoc comments for every class and every constructor, method, and field of the class.
  2. Write a package.html description for every package, and make it the overview that explains the concepts that describe the package and how those concepts fit together.
  3. Use @param, @return, and @throws to explain what each method does.
  4. Make your javadoc comments the specification of the interface to your code.
  5. Write the javadoc comments for each interface general and appropriate enough to cover all the classes that implement that interface, and let each of the classes inherit the javadoc comments where appropriate.

Someone should be able to use your packages, classes, and methods correctly after reading just the javadoc description.

Make it easy to describe

If it is hard to come up with javadoc comments and variable/method/class/package names that clearly describe what your code is doing, then your code is probably either

  1. doing the wrong thing, or
  2. organized in the wrong way.

Try writing a simpler, clearer description. Instead of struggling to write a description that matchs the code, write a clear description and make the code match that. Reorganize your design so that you can describe the components easily and simply.

Layout

These rules have a long history of helping people write better code.

  1. Use blank lines to separate conceptual units in your code.
  2. Line up things that go together. For exaample, if you have an if ladder with one or more else ifs, put a /**/ comment after the first if keyword so the conditions are lined up, and use whitespace to line up other things that go together (like the braces, or like the parts of the @param comments in the example further down).
      if /**/ (null == result)       {  …  }
      else if (0 == result.length()) {  …  }
      else                           {  …  }
    
  3. Java (and most other languages) let you omit the braces for an if, else, while, or for that has just one statement. But don't do it! Put the braces in anyway. The classical reason is that later someone will want to add a second statement, they will forget to put in braces, and the bug will be almost impossible to find.
      // NO!
      if (onlyOne) m = 1;  // this is bad
    
      // Yes.  Always use braces.
      if (onlyOne) {  m = 1;  }
    

Use the compiler's checks to the fullest

  1. In comparing an lvalue with an rvalue for equality, always put the rvalue on the left; that way, if you or someone later puts = instead of ==, the compiler will flag a syntax error.
      // NO!
      if (ref == null) {  …  }  // this is unwise
    
      // Yes.  Put the rvalue on the left.
      if (null == ref) {  …  }
    

    An lvalue (pronounced ell-value) is an expression that can be on the left side of an assignment — a variable, or an expression that produces a variable. An rvalue (pronounced are-value) is an expression that can only be on the right side of an assignment — a value, or an expression that produces a value.) 

  2. Use the @Override annotation to identify methods you think are overriding methods in a superclass. The compiler generates an error message for every such method that doesn't in fact override a superclass method.
      //  The compiler will catch that the method name is misspelled:
      @Override
      public String toStrink() { … }
    
  3. Define your classes so that they represent behavior, so that code that asks for inappropriate behavior will be code that tries to use the wrong class, which the compiler may be able to catch as a type or class cast error.
  4. Whenever possible:
    • Use immutable objects.
    • Make variables final.
    • Use java.util.Collections's static unmodifiableX() methods to make unmodifiable views of collections, and use those views rather than the original modifiable collections.
    • Design your classes so that objects of those classes are immutable.
    Then any attempt to change them will be caught as a syntax error.
  5. In general, write your code so that semantic bugs (which are hard to identify and fix) have to be expressed using syntactic bugs (which the compiler catches and which are easy to fix).

Immutability is your friend

Where possible, make objects immutable. That is, design your classes so that the value of each object of a class is set when the object is constructed, and never changed. Taking two examples from java.lang: String objects are immutable, and StringBuffer objects are mutable. Strings are much easier to reason about and get right.

Java provides the final keyword, whose effect is related but different: if you declare a variable, parameter, or attribute final then it cannot be changed to refer to a different value or object. That is quite useful! But note that for example a final StringBuffer variable is still mutable;  the final just means that no other StringBuffer can be assigned to the variable.

Researchers have long known that using immutable objects makes it far, far simpler to construct a proof of correctness for a program or an aspect of a program. More recently, the best practitioners have realized that it also makes it far, far simpler to understand and reason about your programs. That means they are easier to design, easier to write, and easier to debug. If an object is immutable, then you don't have to take its context and history into consideration, and context and history are the aspects that are the most difficult to understand and reason about.

Assertion checking

As you write your code, put in assertion checks for every condition you are assuming is true:

  if (!conditionYouAssume) {
    throw new AppropriateRuntimeException("Informative message");
  }

(Don't include such exceptions in the throws clause of the method, as they are not there to be caught but to kill the process and print a stack trace.) 

If you have access to my exception package, you will find there a wide selection of kinds of exceptions to choose from. If you don't have access to an appropriate exception, write a new exception class to use (it's easy and fun).

A good rule of thumb is: if you realize you are assuming something while you are writing code, stop and put in assertion code that checks that the assumption holds at the point where your code assumes it and throws an informative exception if the assumption is violated. Assertion checks are always appropriate if:

  1. the set of acceptable values for a variable is smaller than the set of possible values, or
  2. the values of two or more related variables must have a specific relation.

At a minimum, write checks of incoming parameter and attribute values for every method. You should include the exceptions for parameter checks in @throws tags for the method's javadoc, with an informative description such as.

    @throws NullPointerException  If _parameter is null.

Assertion checking is crucial for software whose external and internal interfaces are unstable, as is almost always the case in research projects.

The interplay between prototyping and testing

Testing is essential, but it's difficult to test code effectively if you don't know what it is supposed to do yet.

If you are in a prototyping situation, as is often the case in writing code for research projects, you should not spend too much time on writing tests (write assertions instead). Just write tests for what you are pretty sure your code is going to have to do.

As the specification for your code stabilizes, add more tests. If your code is something whose correctness is going to be essential, then write a full set of tests when the specification settles.

Run your tests often, even early on when you don't have many.

My personal prejudices

  1. There are several styles of bracing. Use this one:
      if (…) {
        …
      }
      while (…) {
        …
      }
    
  2. If you indent with spaces, use two per level.
      if (…) {
        while (…) {
          …
        }
      }
    
  3. If you put a braced statement on a single line, put two spaces between it and the braces, both before and after.
      if (…) {  x = 2;  }
                ^^      ^^
    
      while (…) {  y += 5;  }
    
  4. Unless you are using Eclipse, which controls javadoc formatting for you, indent your javadoc comments like so:
      /**
        Align the start and end markers with each other
        and the entity you are commenting.
      */
      public interface Javadoc {
    
        /**  Short ones can go on a single line (two spaces before and after).  */
        String oneLiners();
    
        /**
          Longer ones have the start marker on a line by itself,
          and the end marker on a line by itself.
          Text is indented two spaces further in.
        */
        String longerOnes();
    
      }
    

    The Eclipse placement of a * at the beginning of each line is troublesome to do in a text editor and not worth the effort.

  5. In the common case of a get method that returns one of the class's attributes, use the same name for both.
      /**
        Returns the left subformula.
      */
      public Formula left() {  return left;  }
    
  6. In the common case of a set method that sets one of the class's attributes, use the same names for everything. Prefix the parameter name with an underscore to distinguish it.
      /**
        Sets the left subformula.
      */
      public void left(Formula _left) {  left = _left;  }
    
  7. Do not use get or set in your method names. Instead, fix the conceptual model you are using for the class, or the names you have given to the concepts. If it seems necessary to use get or set in order to distinguish the methods when searching the source code, then change to a capable text editor or development environment, or learn to use regular expression searching in your current editor.

Some interesting links

Bergin: Coding patterns

flip bgunflip