This page documents the standard adopted for Java code in the Cask project(s).

All committers are expected to follow these standards; Checkstyle or similar (Lynt) is used to check compliance.

CDAP 6.9+

CDAP starting from version 6.8 uses slightly relaxed Google Coding Standards.

CDAP 6.8 and before

Summary

The main things for layout purposes in the standard are:

if (x == 5) {
  System.out.println("Hello");
}

rather than  

// WRONG
if (x == 5}
{
  System.out.println("Hello");
}
if (x == 5) {
  System.out.println("Hello");
}

rather than 

// WRONG
if (x == 5)
  System.out.println("Hello");

Introduction

This document describes two types of coding standard:

1. Mandatory standards must be followed at all times.
2. Recommended standards should in general be followed but in particular cases may be omitted where the programmer feels that there is a good reason to do so.

Code that does not adhere to mandatory standards will not pass the automated checks (or a code review if the guideline is not stylistic).

Source files

This section defines the general rules associated with the contents of a Java source file and the order in which the each part should be presented. No rules on programming style, naming conventions or indentation are given here.

  1. Java source files must have a ".java" suffix (this will be enforced by the compiler) [mandatory].
  2. The basename of a Java source file must be the same as the public class defined therein (this will be enforced by the compiler) [mandatory].
  3. Only one class should be defined per source file (except for inner classes and one-shot uses where the non-public class cannot conceivably be used outside of its context) [mandatory].
  4. Source files should not exceed 1500 lines [recommended].
  5. No line in a source file should exceed 120 characters [mandatory].
  6. The sections of a source file should be presented in the following order [mandatory]:
    1. Copyright Information
    2. File information comment (see rule 7 below).
    3. Package name (see rules 1 to 3 in the section 2.1 above and rule 8 below).
    4. Imports (see rules 9 to 10 below).
    5. Other class definitions.
    6. Public class definition.
  7. Every class that is to be released must be a member of a package [mandatory].
    1. Rationale: classes that are not explicitly put in a package are placed in the unnamed package by the compiler. Therefore as the classes from many developers will be being placed in the same package the likelihood of a name clash is greatly increased.
  8. All class imports from the same package should be grouped together. A single blank line should separate imports from different packages [recommended]. The actual order of imports must be as follows, with each group ordered lexically:
    1. all co.cask
    2. all other but non-java
    3. all java[x]
  9. No import package.* allowed. Classes must be imported one by one [mandatory].
  10. Use Javadoc tags and use HTML mark-up to enhance the readability of the output files [mandatory].
  11. Every package should provide package-info.html [recommended].

Compilation

This section defines the general rules associated with results of compiling a Java source file.

  1. Compiling a Java source should not result in undefined documentation compilation errors [mandatory].
  2. Compiling a Java source should result in no warnings [mandatory].

Java Elements

This section gives advice on coding the various elements of the Java programming language.

Class definitions

This section gives guidelines for class and interface definitions in Java. The term class in this section is used more broadly to mean class and interface:

  1. Class names should start with a capital letter with every subsequent word capitalised, for example: DataProcessor [mandatory].
  2. The name of exception classes should end in the word exception, for example: UnknownMungeException [mandatory].
  3. Class names should in general not be overloaded. For example, defining a class "com.foo.bar.String" should be avoided as there is already a class "java.lang.String" [recommended].
    Rationale: adhering to this rule reduces the likelihood of confusion and means that the use of fully qualified class names should not be required.
  4. Class name should not be plural. For example, `ProgramManager` not `ProgramsManager` [recommended]. 
  5. The definition of the primary class (i.e. the class with the same name as the java file) should start in column 0 of the source file. Inner class definitions should be indented 2 spaces more than their enclosing class [mandatory].
  6. Declare a class as final only if specialization will never be required and improved performance is essential. With modern JVMs there in fact may be no performance advantage. Warning: use of final limits code reuse [mandatory].
  7. For all but simplest classes the following methods should have useful definitions [recommended]:
    public boolean equals(Object obj)
    public int hashCode()
    public String toString()
    
  8. The order of presentation of the sections in a class should be [mandatory]:
  9. Variables
  10. Methods Variables

    This section gives guidelines for class and instance variable definitions in Java. In this section if a rule uses the term variable rather than instance variable or class variable, then the rule applies to both types of variable.

  11. The order of presentation of variables in a class definition should be [recommended]:
    1. private, protected, public: static final variables (aka constant class variables).
    2. private, protected, public: static variables (aka class variables).
    3. private, protected, public: final variables (aka constant instance variables).
    4. private, protected, public: variables (aka instance variables).
      It should be noted that as Javadoc will automatically order variables in a consistent manner, rigid adherence to this rule is not necessary.
  12. Variable modifiers must be presented in the following order: static, final, transient, volatile [mandatory].
  13. The names of static final variables should be upper case with subsequent words prefixed with an underscore [mandatory]. For example:
    public static final int NOT_FOUND = -1;
    
  14. When a subclass refers to a static final variable defined in a parent class, access should be qualified by specifying the defining class name [mandatory]. For example: use ParentClass.MAX rather than MAX.
  15. The names of variables (other that static final) should start with a lower case letter. Any words that are contained in the rest of the variable name should be capitalised [mandatory]. For example:
    String name;
    String[] childrensNames;
  16. Variables must not be named using the so-called Hungarian notation [mandatory]. For example:
    int nCount = 4; // not allowed
    
  17. Only one variable may be defined per line [mandatory].
  18. Variable declarations should be indented 2 spaces more than their enclosing class [mandatory].
  19. All variables should be preceded by a comment that explains what the variable is for, where it is used and so forth, unless it is obvious. The comment should not be a Javadoc, unless it is a public or protected variable.
  20. All public constants must be preceded by a Javadoc that explains the meaning of the constant [mandatory].
  21. Never declare instance variables as public unless the class is effectively a "struct" [mandatory].
  22. Never give a variable the same name as a variable in a superclass [mandatory].

Ensure that all non-private class variables have sensible values even if no instances have been created (use static initialisers if necessary, i.e. "static { ... }") [mandatory].
Rationale: prevents other objects accessing fields with undefined/unexpected values.

Methods

This section gives guidelines for class and instance method definitions in Java. In this section if a rule uses the term method rather than instance method or class method, then the rule applies to both types of method.

Ensure that non-private static methods behave sensibly if no instances of the defining class have been created [mandatory].

Expressions

This section defines the rules to be used for Java expressions:

All binary and ternary operators,with the exception of ".", should be separated from their operands by a space [mandatory].

Statements

Simple Statements

This section defines the general rules for simple Java statements:

In method calls, there should be no spaces before or after the parentheses [mandatory]. For example:

munge (a, 10);    // Incorrect!
munge(a, 10);     // Correct.
Compound Statements

This section defines the general rules associated with compound statements in Java:

In switch statements - a default case must be present and should always be the last case [mandatory].

General

This section gives general rules to be followed when programming in Java:

Use final local variables where possible to help avoid errors in code [recommended]. For example:

public void foo() {
    final int x = dataSource.getCount();
    // do things with x
    // ...
}

ThreadLocal

ThreadLocal is a nice Java construct that allows you to isolate state across different threads (https://docs.oracle.com/javase/7/docs/api/java/lang/ThreadLocal.html). However, uncareful usage of ThreadLocal (or InheritableThreadLocal) can easily lead to memory leaks. As a rule of thumb, they are safe to use if the thread executing the code is short lived. Otherwise, care must be made to remove the ThreadLocal once it is no longer needed.


The longer explanation is that each thread contains a Map of all the ThreadLocal objects created by any code executed by that Thread. For example:

These objects are garbage collected if the thread goes away. However, if thread is long running (for example, it is used in a thread pool), these objects will never get garbage collected. In the example above, every time an instance of ExampleClass is created, a new entry will be added to the ThreadLocalMap inside the current Thread. If the thread never exits, memory will leak until the process dies. See  for an example of this in the past.


If you are not absolutely certain that the Thread using the ThreadLocal is short-lived, you must be sure to remove the ThreadLocal once it is no longer needed. Much like closing an InputStream in a finally block, classes that use a ThreadLocal must have a way to release all their resources. In the example below, a close() method is added to the ExampleClass that removes the ThreadLocal. After this, we can see that the Map in the ThreadLocal no longer has the objects.

Another option if possible is to make the ThreadLocal static so that there is only instance per thread.

Exceptions

This section gives general guidance on the use of exceptions when programming in Java.