TS-33: Java

This technical standard provides guidelines for writing Java code that is clear, maintainable, and consistent. It is based on Google’s Java Style Guide, which is widely adopted in the IT industry. Other sources are listed in the references section at the end of this document.

Terminology

Throughout this document, the following words shall have the following meanings:

  • "Class-like constructs" means any ordinary classes, enums, interfaces, or annotation types (@interface).
  • "Block-like construct" refers to the body of a class, method, or constructor, and also to array initializers, static initializers, and other similar constructs.
  • "Members" means all fields, methods, constructors, and nested classes within a class or other class-like structure.
  • "Comments" refers only to implementation comments, while "Javadoc" refers to inline API documentation that is encoded as comments.

Source files

Each source file SHOULD contain exactly one class-like construct. However, in special circumstances, a source file MAY have exactly one top-level public class plus additional class-like constructs that are deliberately tightly coupled to the main class and that are shared with no other classes. The top-level public class MUST be the first construct within the file.

Source files are distinguished by the .java file extension, while Java bytecode files have the .class extension. The file names MUST match exactly – including the exact letter case – the name of the main class-like construct they contain.

The contents of source files MUST be laid out in the following order, from top to bottom:

  1. License or copyright notice, if required.
  2. Package statement.
  3. Import statements for internal classes, listed alphabetically.
  4. Import statement for third-party package dependencies, listed alphabetically.
  5. The main top-level class-like construct, eg. a public class.
  6. Other class-like constructs used by the main construct.

Each section MUST be separated by a single blank line. Class-like constructs, block-like constructs, and members MUST also be separated by a single blank line. Javadocs MUST be preceded by a single blank line, except the first file-level Javadoc, which MAY start on line 1.

Encoding

Source files MUST be encoded using UTF-8.

Source files MUST use Unix-style line endings, which means using the line feed (LF) character, which is represented by the escape sequence \n. Source files MUST NOT use Windows-style line endings, which is a carriage return and line feed (CRLF) pair and represented by the escape sequence \r\n.

Whitespace characters included in source code MUST be limited to the line termination sequence and the horizontal space character. Tab characters MUST NOT be used for indentation.

Other whitespace characters MAY be included only in string and character literals (they MUST NOT be included in any other parts of the code) and they MUST be represented by escape sequences. Whitespace characters that have a special escape sequence in Java MUST be encoded using that escape sequence.

Available whitespace escape sequences in Java

Escape sequence

Description

\t

Insert a tab in the text at this point.

\b

Insert a backspace in the text at this point.

\n

Insert a newline in the text at this point.

\r

Insert a carriage return in the text at this point.

\f

Insert a form feed in the text at this point.

\'

Insert a single quote character in the text at this point.

\"

Insert a double quote character in the text at this point.

\\

Insert a backslash character in the text at this point.

System.out.println("She said \"Hello!\" to me.");

For other whitespace characters, either their octal (eg. \012) or their Unicode code point (eg. \u000a) SHOULD be preferred over including the literal whitespace character. Optionally, you can describe encoded characters in an end-of-line comment. The goal is to make it as easy as possible for others to identify special whitespace characters in code.

System.out.println("\u2004"); // three-per-em space

Non-whitespace (ie. printable) characters outside of the ASCII range MAY be encoded using either their actual Unicode character (eg. ) or that character’s Unicode escape sequence (eg. \u221e). The choice of which encoding to use is at the discretion of the developer, but the choice SHOULD be determined by the readability and understandability of the code.

/*
This code is perfectly clear. The "μ" character can be printed
verbatim, rather than be represented by an escape sequence, and
no comments are necessary.
*/
String unitAbbrev = "μs";

For all characters that are encoded using escape sequences, except for those that are widely recognized (\t, \n, etc.), a comment SHOULD be included to explain the meaning of the escape sequence. End-of-line // comments SHOULD be used for this purpose.

return "\ufeff" + content; // byte order mark

Naming conventions

Spelling

All file names, code, comments, and Javadocs MUST be written in English, with American English preferred for spelling.

Identifiers

All identifiers MUST be composed only of ASCII letters and digits and, in a small number of cases, underscores. Thus, each valid identifier is matched by the regular expression \w+.

Special prefixes or suffixes SHOULD NOT, generally, be used on identifiers. For example, do not prefix variables with s_ to indicate that they are static, or suffix interfaces with I to indicate that they are interfaces.

Package names

Package names MUST use all lower case letters and digits, and no underscores. Java does not allow hyphens in package names, so that’s not even an option.

Consecutive words are simply concatenated together, with no special formatting for word delimitation.

  • com.example.formvalidator
  • com.example.form_validator
  • com.example.formValidator
  • com.example.form_validator
  • com.example.form-validator ✗ (illegal package name)

The convention for writing package names in lower case has been established to avoid conflicts with the names of classes and interfaces (identifiers in Java are case-sensitive).

The convention of using a reverse domain name – eg. com.example – for the top-level namespace of a package is also long-established in the Java community. The purpose of this convention is to ensure that package names are unique across different organizations and projects – across the whole global Java ecosystem. Since a domain name is unique to the person or organization who owns it, this convention guarantees uniqueness of package names globally.

However, for application code that will not be shared with others, the reverse domain name convention is not necessary. Better in this case to choose a codename for each software project, which is unique internally within the organization. Using a codename rather than the application’s brand name helps to decouple the code from the product marketing, allowing the latter to be changed without substantial code refactoring.

In choosing codenames for their software projects, organizations may choose a theme, such as the names of planets, cities, or characters from books or movies.

adelaide.webapi.io.controllers.cli
adelaide.webapi.io.controllers.http
adelaide.webapi.kernel.commands
adelaide.webapi.kernel.config
adelaide.webapi.kernel.jobs
adelaide.webapi.model.entities
adelaide.webapi.model.repositories
adelaide.webapi.system.dao
adelaide.webapi.system.services
Examples of internal/private package names

Package names may be a mix of plural and singular forms. Use your judgment. The general principle is that the plural form should be used for packages with homogenous contents and the singular for packages with heterogeneous contents. Most packages will be containers for software components of the same type (homogenous collections), and therefore the plural form will be appropriate: "controllers", "documents", "entities", "services", "repositories", etc. An exception would be for collections of components that implement a design pattern identified by an abbreviation such as "dto" or "dao"; appending these with an "s", while more consistent, would only increase confusion.

Some packages will be containers for diverse components from which a discrete subsystem is composed, such as a GUI or library. For many of these packages the singular form will be more appropriate, eg. "gui", "lib", "util". Similarly, configurations should go in a "config" package.

Class and interface names

Classes and interfaces MUST be named using UpperCamelCase.

Class names are typically nouns or noun phrases. They SHOULD be descriptive and unambiguous, and SHOULD NOT be overly long. Good examples of class names include Character, ImmutableList, PriorityQueue, and UrlConnection.

Interface names MAY also be nouns or noun phrases, eg. List, but MAY also be adjectives or adjective phrases, eg. Readable, Closeable, or Runnable.

Classes from which objects are created SHOULD be named using a singular noun or noun phrase, eg. UserService, UserEntity, UserRepository, etc. Where classes are merely containers for static methods and constants, they MAY be named using a plural noun or noun phrase, eg. DataAccessUtilities, ValidationRules, etc.

Interfaces SHOULD follow the same naming conventions as classes, but with a suffix that distinguishes them from instantiable classes. Within the Java standard library, interfaces are typically named with a suffix of "able" or "ible", eg. Runnable, Closeable, Serializable, Comparable, Iterable, etc. This convention MAY be carried over into userland libraries and applications.

Interfaces SHOULD NOT mirror exactly the names of the classes that implement them – this is a code smell, since it suggests the interface is too tightly coupled to a single implementation. But if there really is no better name for an interface, the interface name MAY take the class name plus the suffix "Contract".

Interfaces SHOULD NOT be prefixed or suffixed with "I" or "Interface". This convention is more common in other languages like C#, but is not widely used in Java.

Test classes MUST have a name that ends with Test. If the test covers a single class, the test class name SHOULD be the name of the class being tested, with Test appended.

Method names

Methods MUST be named using lowerCamelCase.

Method names SHOULD, typically, be verbs or verb phrases, eg. sendMessage, stop, computeTotal.

Underscores MAY be used in JUnit test methods to separate logical components of the name, with each component written lowerCamelCase, eg. transferMoney_deductsFromSource.

Field, variable, and parameter names

Fields, variables (including local variables), and parameters MUST use the same naming convention as methods: lowerCamelCase.

These SHOULD mostly be nouns or noun phrases, eg. index, height, computedValues.

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

Constant names

A "constant" is defined here as a static final field whose contents are deeply immutable and whose methods have no detectable side effects (merely intending to never mutate the object is not sufficient). Examples include primitives, strings, immutable value classes, and anything set to null.

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

Constants MUST be named using UPPER_SNAKE_CASE: all uppercase letters, with words delimited by a single underscore.

Constant names are typically nouns or noun phrases.

/*
Constants.
*/

static final int NUMBER = 5;

static final ImmutableList<String> NAMES = ImmutableList.of("Ed", "Ann");

static final Map<String, Integer> AGES = ImmutableMap.of("Ed", 35, "Ann", 32);

/* Joiner is immutable. */
static final Joiner COMMA_JOINER = Joiner.on(',');

static final SomeMutableType[] EMPTY_ARRAY = {};

/*
Not constants.
*/

static String nonFinal = "non-final";

final String nonStatic = "non-static";

static final Set<String> mutableCollection = new HashSet<String>();

static final ImmutableSet<SomeMutableType> mutableElements = ImmutableSet.of(mutable);

static final ImmutableMap<String, SomeMutableType> mutableValues =
    ImmutableMap.of("Ed", mutableInstance, "Ann", mutableInstance2);

static final Logger logger = Logger.getLogger(MyClass.getName());

static final String[] nonEmptyArray = {"these", "can", "change"};

Type variable names

Type variables SHOULD be named in one of two ways:

  • A single capital letter, optionally followed by a single numeral, eg. T, E, X, T2, T3.
  • The class or interface name from which the type variable is derived, with the capital letter T appended, eg. RequestT.

Annotation names

Surprisingly, there are no well-established conventions for naming annotation types in Java. The prevailing convention seems to be UpperCamelCase, but this is far from universal.

This coding standard RECOMMENDS that annotation types be named using UpperCamelCase, eg. @CheckReturnValue, for consistency with the prevailing convention.

Annotation names MAY be verbs or nouns, depending on their purpose.

Code style

Indentation

Each time a new block or block-like construct is opened, the code MUST be indented by an additional two spaces.

Tab characters MUST NOT be used for indentation. IDEs SHOULD be configured to automatically replace tab characters with spaces.

Increase the indentation by one level for each nested block or block-like construct. When the nested block ends, the indent returns to the previous level.

Indentation of comments and Javadocs MUST align with the code to which they are related.

Line length (column limits)

There MUST be no more than one statement per line.

Most lines should be under 80 characters in length, including preceding whitespace for indentation, and SHOULD NOT exceed 100 characters. Lines that exceed the hard limit SHOULD be line-wrapped (see below).

Package and import statements MAY exceed the column limits; they MUST NOT be line-wrapped.

Other code MAY exceed the column limits, but only where implementing line-wrapping will reduce its readability and understandability (eg. command lines written in a comment) or where obeying the line-length rules is simply not possible (eg. for long URLs in comments).

Line-wrapping

The term "line-wrapping" refers to the practice of breaking a single statement across multiple lines. This is typically done to keep line lengths short, but authors MAY use line-wrapping at their discretion to improve the readability of code (even where the code does not exceed the column limits).

There are no deterministic rules for line-wrapping in Java, but the following guidelines SHOULD be followed:

  • Look to refactor the code before line-wrapping is implemented. Can long statements be broken into multiple shorter ones? Can some of the code be extracted into methods?
  • Otherwise, prefer to break at a higher syntactic level rather than on lower-level breaks. Examples:
    • Break before non-assignment operators as well as operator-like symbols such as the dot separator (.) and double colons for method references (::)
    • Break after assignment operators.
    • Break after the arrow in a lambda expression if the lambda body is a single un-braced statement.
    • Commas SHOULD stay attached to the token that precedes them.
    • Constructors and method names SHOULD stay attached to their opening parentheses.
MyLambda<String, Long, Object> lambda =
    (String label, Long value, Object obj) -> {
      // …
    };

Predicate<String> predicate = str ->
    longExpressionInvolving(str);

The continuation lines SHOULD be indented by an additional four spaces – double the normal indentation level, for better clarity.

Brace style

Braces MUST be used with if, else, for, do, and while statements, even when the body of the statement is empty or contains only a single statement.

For empty block-like constructs, the block SHOULD be written as {} on the same line as the statement that opens the block.

void doNothing() {}

It is also okay to use this style for empty blocks within multi-block statements. (This is a relaxation of the Google Java Style Guide, which forbids this.)

try {
  doSomething();
} catch (Exception e) {}

For non-empty block-like structures, the K&R style – also known as "Egyptian brackets" – MUST be used. The rules of this style are:

  • No "hanging opening bracket", ie. no line break before the opening brace, in most cases. The opening is placed at the end of the line that begins the block-like construct.
  • A line break after the opening brace.
  • A line break before the closing brace.
  • A line break after the closing brace, but only if that brace terminates a statement or the body of a method, constructor, or named class. Thus, else, catch, finally, and while keywords go immediately after the closing brace of the preceding block, because these represent a continuation of the preceding block statement.

Authors MAY deviate from the K&R style where doing so improves readability. For example, opening braces MAY be placed on a new line after very long statements, or where blocks are used only to limit the scope of local variables. And where a closing brace is followed by a comma, semicolon, or other punctuation, normally that punctuation would be placed on the same line as the closing brace.

Examples from the Google Java Style Guide:

return () -> {
  while (condition()) {
    method();
  }
};

return new MyClass() {
  @Override
  public void method() {
    if (condition()) {
      try {
        something();
      } catch (ProblemException e) {
        recover();
      }
    } else if (otherCondition()) {
      somethingElse();
    } else {
      lastThing();
    }

    {
      int x = foo();
      frob(x);
    }
  }
};

Vertical whitespace

A single blank line SHOULD be included in the following scenarios between consecutive members or initializers of a class or other class-like constructs: fields, constructors, methods, nested classes, static initializers, and instance initializers.

Logical groupings of fields MAY be created by omitting blank lines between two or more consecutive fields.

Single blank lines MAY be added wherever doing so improves the readability of the code (eg. using vertical whitespace to separate logical sections of a method) or helps to make clearer the code’s structure (eg. organizing fields into logical groupings).

Multiple consecutive blank lines SHOULD NOT be included in any Java code.

Horizontal whitespace

Besides what is required by the Java language, a single ASCII space character SHOULD appear in the following scenarios:

  • To separate reserved words such as if, for, and catch from the opening parenthesis that follows them on the same line.
  • To separate reserved words such as else and catch from the closing curly braces that precede them on the same line.
  • Before most opening curly braces, with a couple of exceptions:
    • @SomeAnnotation({a, b}) ** String[][] x = {{"foo"}};
  • Between the type and variable of a declaration: List<String> list.
  • Inside the curly braces of an array initializer: new int[] { 1, 2, 3 }.
  • After ,, ;, and :.
  • After the closing parenthesis of a cast.
  • On both sides of binary and ternary operators.
  • Around the following operator-like symbols:
    • The ampersand in a conjunctive type bound: <T extends Foo & Bar>.
    • The pipe for a catch block that handles multiple exceptions: catch (FooException | BarException e).
    • The colon (:) in an enhanced for statement.
    • The arrow in a lambda expression: (String str) → str.length()
  • Before and after a double slash (//) that begins an end-of-line comments, and between the double slash and the code where this comment notation is used to comment-out code.

Authors MAY include additional spaces before end-of-line comments to achieve vertical alignment.

System.out.println(sorted);   // [15, 23, 51, 80]
System.out.println(unsorted); // [80, 51, 23, 15]

There MUST NOT be any superfluous whitespace at the end of lines. It is strongly RECOMMENDED to configure both IDEs and automation pipelines to automatically remove trailing whitespace, which can otherwise creep in as a byproduct of refactoring and can produce unnecessary diffs in version control.

Programming constructs

Import statements

Wildcard imports, static or otherwise, SHOULD NOT be used.

Imports SHOULD be grouped by:

  • Static imports
  • Non-static imports

There SHOULD be exactly one blank line between the two groups to separate them. Within each group, imports SHOULD be sorted alphabetically based on the names of the imports. There SHOULD NOT be any other blank lines between import statements.

Import statements SHOULD NOT be line-wrapped. Import statements MAY exceed the column limits.

Static imports SHOULD NOT be used for static nested classes. They SHOULD be imported with normal imports.

Variable declarations

Each variable declaration (field or local) MUST be on its own line and declare exactly one variable. Declarations such as int a, b; MUST NOT be used, except in the header of a for loop.

Local variables SHOULD NOT be habitually declared at the beginning of their containing block. Instead, local variables SHOULD be declared close to the point they are first used. The aim is to minimize the scope of variables.

Local variable declarations SHOULD typically have initializers, or SHOULD be initialized immediately after the declaration.

Classes and interfaces

There SHOULD be a logical ordering to the contents of classes and other class-like constructs. There is no single "correct" ordering that works well for all classes, but the following order is a good starting point:

  1. Class (static) variables
  2. Instance variables
  3. Constructors
  4. Methods

Class and instance fields MAY be ordered by visibility: first public, then protected, then package-scoped (no modifier), then private. But it is, generally, better to order and group methods logically, rather than by visibility (public, protected, private), type (static, instance), or by name (eg. alphabetical ordering). Authors SHOULD order the contents of a class in a way whatever way they feel most helps to understand the class’s purpose and logic.

However, it is REQUIRED that methods of a class that share the same name, but which have different parameters, be grouped together. This requirement also applies to variadic constructors.

Constructor and method declarations MUST be separated by a blank line. Constants and fields MAY be. (See vertical whitespace.)

Enums

An enum class with no methods and no documentation on its constants MAY be formatted as a single line, similar to an array initializer.

private enum Suit { CLUBS, HEARTS, SPADES, DIAMONDS }

Otherwise, the enum constants SHOULD be listed on separate lines, with a comma after each constant, and the opening brace on the same line as the enum name. There SHOULD NOT be any blank lines within enum bodies, except where required around comments.

private enum Answer {
  YES {
    @Override
    public String toString() {
      return "yes";
    }
  },
  NO,
  MAYBE
}

Enums should be named using singular forms. The thinking is that you’re not selecting multiple Protocols, but rather one Protocol of the possible choices.

enum Protocol { HTTP, HTTPS, FTP }

Modifiers

Class and member modifiers, when present, SHOULD appear in the order recommended by the Java Language Specification, which is:

public protected private abstract default static final sealed non-sealed transient volatile synchronized native strictfp

For classes, the public access modifier MUST be added only if the class is intended to be used outside of its package.

For members, access modifiers SHOULD be added in most cases. It is good practice to be explicit about the access level of class methods and data members, even where the default access level is appropriate.

Most instance variables SHOULD be private, to adhere to the principle of data hiding. Methods, most of the time, will be public, unless the method is intended to be used only within the current class or a derived classes, in which case it SHOULD be protected, or private on final classes.

Generally, package-scoped members – which have no modifier, as this is the default scope – SHOULD be avoided, particularly in applications. However, using package-level visibility can be useful in some cases. It is particularly useful in the context of libraries, and also in the implementation of the aggregate root design pattern.

Annotations

Field annotations SHOULD all be listed on the same line.

@Partial @Mock DataLoader loader;

Type-use annotations MUST appear immediately before the type they are annotating.

final @Nullable String name;

public @Nullable Person getPersonByName(String name);

Annotations applying to a class MUST each be listed on separate lines before the class declaration, and immediately after any preceding Javadoc.

@Deprecated
@CheckReturnValue
public final class Frozzler {
  // …
}

The rules for method and constructor annotations are the same.

@Deprecated
@Override
public String getNameIfPresent() {
  // …
}

There are no specific rules for formatting annotations on parameters or local variables.

@Override

The @Override annotation MUST be used on all methods that are intended to override a method in a superclass or an interface.

There is one exception: @Override MAY be omitted when the parent method is @Deprecated.

Static members

References to static class members MUST be qualified with the name of the class, not with a reference or expression of that class’s type.

Foo myFoo = new Foo();

Foo.doSomething(); // Good
myFoo.doSomething(); // Bad
somethingThatReturnsFoo().doSomething(); // Very bad

Exceptions

It is very rarely correct to do nothing in response to a caught exception. Where you do this, the reason MUST be documented in a comment within the catch block.

try {
  int i = Integer.parseInt(response);
  return handleNumericResponse(i);
} catch (NumberFormatException ok) {
  /* It's not numeric; that's fine, just continue. */
}

return handleTextResponse(response);

In tests, the following is a very common idiom for ensuring that the code under test does throw an exception of the expected type. A comment within the catch block is not necessary here.

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

Switch statements

After a switch label (case <label>:, default:), there SHOULD be a line break, and then the indentation increased by one level (ie. two spaces) for the statement group.

The comment // fall through SHOULD be included at the bottom of any statement group where execution will or might continue into the next statement group. This special comment is NOT REQUIRED for the last statement group. It is also NOT REQUIRED for empty statement groups.

switch (input) {
  case 1:
  case 2:
    prepareOneOrTwo();
    // fall through
  case 3:
    handleOneTwoOrThree();
    break;
  default:
    handleLargeNumber(input);
}

Each switch statement MUST include a default statement group, even if it has no code. Only a switch statement for an enum type MAY omit the default statement group, and only if it includes explicit cases that cover all possible values of the type (this enables static analysis tools to issue warnings if cases are missed).

Types

Numeric literals

An uppercase L suffix MUST be used for long literals, eg. 3000000000L, not 3000000000l. This is because the lowercase l can be easily confused with the digit 1.

Arrays

Array initializers MAY be treated as block-like constructs. The following styles are all valid.

new int[] { 0, 1, 2, 3 }

new int[] {
  0, 1, 2, 3
}

new int[] {
  0,
  1,
  2,
  3
}

Authors SHOULD NOT write C-style array declarations. The square brackets SHOULD form part of the type, not the variable:

/* ✓ */
String[] args

/* ✗ */
String args[]

Comments

Java supports three comment notations:

  • //
  • /* … */
  • /** … */

The code below represents this style guide’s RECOMMENDATIONS for using Java’s single-line (//) and multi-line (/* … */) comment syntax. These are used for implementation comments, while Javadoc comments (/** … */) are used for API documentation comments.

The single-line implementation comment syntax is used in two use cases:

  • To comment-out code.
  • For short end-of-line comments that decode or explain a value assigned, returned, or printed by the statement.

Java’s multi-line implementation comment syntax, /* … */, SHOULD, in fact, be used for both single-line and multi-line implementation comments. For short comments that can fit between the indentation level and the soft line limit, the opening /* and closing */ SHOULD be written on the same line as the comment. But as soon as the comment text needs to be wrapped to two or more lines, the opening /* and the closing */ SHOULD be bumped to their own lines.

int num1 = 7;
int num2 = 5;
// int num0 = 0;

/*
Modulus operator (%) returns the remainder after the first operand
is *evenly* divided by the second operand. In this case, 7 / 5 = 1,
with a remainder of 2.
*/

int modulus = num1 % num2;
System.out.println(modulus); // 2

/* 7 divides evenly into 3 twice (3x2=6) with a reminder of 1 (7-6=1). */
System.out.println(7 % 3); // 2

/*
The modulus operator is often used to determine whether a number is
even or odd. If x % 2 is 0, then x is even, otherwise it is odd.
*/

System.out.println(6 % 2); // 0
System.out.println(7 % 2); // 1

Where the multi-line comment syntax /* … */ is used to encapsulate a single-line comment, there MUST be exactly one space after the opening /* and another before the closing */. The single-line comment syntax // MUST be followed by exactly one space and then the code or value.

Block-level comments MUST be indented to the same level as the code to which they relate.

Multi-line block-level comments SHOULD have an empty line both before and after the comment block. Single-line block-level comments SHOULD have an empty line before them, and MAY have a blank line after.

Optionally, additional empty lines MAY be written within the text of block-level comments, to break it up into paragraphs. This is particularly beneficial for the readability of very long comments.

All text within /* … */ comments MUST be written in full sentences, each starting with a capitalized word and terminated by a period (full stop).

Implementation comments SHOULD only communicate information that is not readily available from the code itself, but which is relevant to the understanding of that code. For example, implementation comments SHOULD be used to document the reasons behind a particular choice of design pattern that, without context, may seem unusual or even counterintuitive to some developers who are looking at the code for the first time.

Implementation comments SHOULD NOT be used to specify the API or behavior of the code (that’s the purpose of Javadocs), nor should they be used to explain things like how to build or test the code (that sort of documentation is better placed in READMEs or other out-of-band documentation).

Javadoc

Javadoc comments are used to document the internal API of a Java program. They are parsed by various tools, including those embedded in IDEs, to generate developer documentation.

Javadoc is used to document the purpose, behavior, specification, and usage of program elements. Javadoc is a developer tool, intended to help yourself and other developers to understand, maintain, change, and extend the code.

Javadoc MUST NOT be used to document implementation details, such as the algorithms used in a method. Standard comments MUST be used for that purpose.

Javadoc SHOULD be used to document all public classes and every public and protected member of such classes. Javadoc MAY be skipped for methods that override a supertype method that is already documented; the supertype method’s documentation is inherited.

Additional Javadoc content MAY be added to other block-level constructs, as needed or desired. Javadoc content SHOULD NOT duplicate the information encoded in method names or signatures, or other adjacent code.

The following is an example of redundant Javadoc. It would be better used to explain the meaning of "canonical name" in this context.

/**
 * Returns the canonical name of this object.
 */
public string getCanonicalName() {
  // …
}

There are two notations for Javadocs: multi-line and single-line:

/**
 * Multiple lines of Javadoc text are written here,
 * wrapped normally...
 */

/** An especially short bit of Javadoc. */

The single-line form SHOULD be used for very short comments with no accompanying block tags such as @return.

In the multi-line form, the Javadoc content MAY be formatted into multiple paragraphs, with each paragraph separated by a blank line (that is, a line containing only the aligned leading asterisk, *).

The first paragraph SHOULD be a brief summary fragment. This MUST be written as a complete sentence, but it SHOULD NOT be a detailed description.

After the first summary paragraph, each subsequent paragraph MUST be prefixed with <p>, immediately before the first word and with no space between it and the first word. Alternatively, the <p> MAY be substituted for other block-level tags such as <ul>.

The standard block tags are:

  • @param for method parameters
  • @return for the return value of a method
  • @throws for exceptions thrown by a method
  • @deprecated to indicate that a method is deprecated

The block tags MUST be each written on a separate line, in the order above. All block tags MUST be followed by a space and then a text description. When the description is long, it SHOULD be wrapped with continuation lines indented four spaces from the position of the @ symbol.

A common mistake is to use block tags in single-line Javadoc comments, eg.:

/** @return the customer ID */

This is invalid Javadoc syntax. This should be:

/** Returns the customer ID. */

Java API specifications

This section covers best practices for using particular Java APIs.

Jakarta Persistence (JPA)

Jakarta Persistence, formerly known as the Java Persistence API (JPA), is a specification for object-relational mapping (ORM) in Java applications. It defines a set of interfaces and annotations for managing relational data, allowing developers to interact with databases using abstractions in the form of Java classes and objects, rather than raw SQL queries.

JPA interfaces provide interoperability between ORM libraries that are compliant to the JPA specification, such as Hibernate and Spring Data JPA. This makes it easier to swap out data persistence implementations without changing – or at least minimizing the changes required in – the application code.

JPA uses JPQL (Java Persistence Query Language) to query data from relational databases. JPQL is similar to SQL, but it operates on the Java entity objects rather than directly on database tables.

import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;

@Entity
public class User {
  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  private Long id;

  private String name;
  private String email;

  /* Getters and setters… */
  // …
}
Example JPA entity class
import org.springframework.data.jpa.repository.JpaRepository;

public interface UserRepository extends JpaRepository<User, Long> {
  // …
}
Basic repository interface

JPA is widely used in enterprise applications and is a key part of the Java EE ecosystem. It is therefore RECOMMENDED to use JPA in Java applications that implement simple interactions with relational databases.

For more complex interactions, such as queries that involve deep joins, or otherwise where performance optimization is a key design constraint, then it may be more appropriate to use a lower-level abstraction (or no abstraction at all).


References