Coding Practices

DDC Style Guide: Java

Naming and other practices in Java source code.

Naming

GJSG 5 Naming is normative, with the amendments below.

GJSC 5.2.3 Method names:

Method names are written in lowerCamelCase.

Method names are typically verbs or verb phrases. For example, sendMessage or stop.

Underscores may appear in JUnit test method names to separate logical components of the name, with each component written in lowerCamelCase. One typical pattern is <methodUnderTest>_<state>, for example pop_emptyStack. There is no One Correct Way to name test methods.

Indeed, there is no One Correct Way to name test methods—or any method, for that matter. However, in this bootcamp, we add the following requirements:

GJSC 5.2.5 Non-constant field names:

Non-constant field names (static or otherwise) are written in lowerCamelCase.

These names are typically nouns or noun phrases. For example, computedValues or index.

GJSC 5.2.6 Parameter names:

Parameter names are written in lowerCamelCase.

One-character parameter names in public methods should be avoided.

GJSC 5.2.7 Local variable names:

Local variable names are written in lowerCamelCase.

Even when final and immutable, local variables are not considered to be constants, and should not be styled as constants.

For this bootcamp, names are further constrained:

  1. Parameter names must consist of 2 or more characters each, except for catch parameters and lambda parameters, which may have single-character names. The following rules in this list do not apply to single-character names for catch or lambda parameter names.

  2. When constructing a lowerCamelCase name, avoid names beginning with a single lowercase character, followed immediately by an uppercase character. Such names are easily mistyped, and can cause problems in automatic generation of setters and getters. For example, while the name of the OAuth authentication standard might intuitively lead to a field name such as oAuthKey, oauthKey is preferred.

  3. Field, parameter, and local variable names of all scalar types (primitives, wrappers, String) except boolean and Boolean, must be singular nouns or noun phrases.

  4. boolean or Boolean fields, parameters, and local variables must be named using adjectives or adjective phrases.

  5. Fields, parameters, and local variables that are references to arrays and collections must be named with plural or collective nouns or noun phrases. For example, in a card game application, we may have a field (or several) of type List<Card>. Both cards and deck would be acceptable names for such a field: the former is a plural noun, and the latter is a collective noun.

  6. Do not name boolean or Boolean fields with prefixes such as is, are, or has. (The is prefix is part of the JavaBeans specification for accessor methods, not fields. Also, all of these prefixes make the field name a verb phrase, rather than an adjectival phrase.)

  7. Do not use Hungarian notation for field, parameter, or local variable names. That is, do not prefix the name with type or role identifiers.

  8. Avoid unnecessary suffixes on field, parameter, and local variable names. For example, prefer

    private List<String> words;
    

    to

    private List<String> wordList;
    

    Similarly, while the m and s prefixes on non-public, non-static and static fields (respectively) are often seen in Java source code (including the Android library source code), these are also unnecessary, and should be avoided.

  9. If a non-static field is intended to act as a primary key value of a persistent instance (e.g., a field annotated with @PrimaryKey in an entity class), prefer the simpler id to {entity name}Id.

Note that there are a few long-standing exceptions to the naming & casing rules listed in GJSG and above. For example, UUID is a class in the Java standard ibrary, written as indicated in UPPERCASE; however, uuid (rather than uUID) is the correct way to use that initialism as a field or variable name.

Programming practices

GJSG 6 Programming Practices is normative, with the amendments and additions below.

GJSG 6.2 Caught exceptions: not ignored:

Except as noted below, it is very rarely correct to do nothing in response to a caught exception. (Typical responses are to log it, or if it is considered “impossible”, rethrow it as an AssertionError.)

When it truly is appropriate to take no action whatsoever in a catch block, the reason this is justified is explained in a comment.

Exception: In tests, a caught exception may be ignored without comment if its name is or begins with expected. The following is a very common idiom for ensuring that the code under test does throw an exception of the expected type, so a comment is unnecessary here.

try {
  emptyStack.pop();
  fail();
} catch (NoSuchElementException expected) {
}

While expected (or ignored) should be used for exceptions that are expected and will not require any special handling, the justification must be explained in a comment within the catch block. For example, the code immediately above is not acceptable, but the following is:

try {
  emptyStack.pop();
  fail();
} catch (NoSuchElementException expected) {
  // Exception is expected if code functions as intended.
}

Types

  1. If a non-static field is intended to act as a non-compound primary key value of a persistent instance (e.g., a field annotated with @PrimaryKey in an entity class), the type of the field must be one of:

    • UUID
    • long or Long
    • int or Integer

    Though the type selected should be independent of the RDBMS being used, this is not always possible. For example, when using SQLite, the most performant—and appropriate—choice for the type of a field intended for use as a non-compound primary key value is long or Long.

Access level modifiers

  1. Class members are declared at the lowest practical access level.

  2. The only fields allowed to have the public access level are those marked final. (Note that interface fields are implicitly public static final, as are the enumerated values of an enum class.)

  3. Non-static fields, even if final, must not be public, except in inner private classes, anonymous classes, or local classes.

  4. Prefer protected accessors and mutators to protected fields.

if-else if ladders

  1. An if-else if statement ladder should include a final else, especially when one or more of the following holds:

    • else if occurs multiple times in the ladder.

    • The purpose of the ladder is to assign one of a number of alternative values to a field.

    • The purpose of the ladder is to assign one of a number of alternative values to a local variable, and that variable is not declared immediately before the ladder.