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,
records, 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:
- License or copyright notice, if required. Whether a license or copyright notice is required at all is a project-level policy decision — some organizations require one on every source file as standard practice — and is not itself prescribed by this standard.
- Package statement.
- Import statements for internal classes, listed alphabetically.
- Import statement for third-party package dependencies, listed alphabetically.
- The main top-level class-like construct, eg. a public class.
- 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.
Special source files
Two file names carry special structures that fall outside the ordinary top-to-bottom layout above.
A package-info.java file holds only package-level declarations and the
package’s own Javadoc: a file-level Javadoc comment (or, in older code, a
package.html file, now superseded by package-info.java), any
package-level annotations, and the package statement itself. It MUST NOT
contain a class-like construct.
A module-info.java file declares a Java module. It contains the module
declaration and its directives, and MUST NOT contain a package statement.
The module directives MUST appear in this order: requires, exports,
opens, uses, provides. Each directive kind forms its own block,
separated from the next by a blank line.
module com.example.myapp {
requires java.sql;
requires com.example.mylib;
exports com.example.myapp.api;
opens com.example.myapp.model to com.example.myapp.persistence;
uses com.example.myapp.spi.Plugin;
provides com.example.myapp.spi.Plugin
with com.example.myapp.plugins.DefaultPlugin;
}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.
Escape sequence | Description |
|---|---|
| Insert a tab in the text at this point. |
| Insert a backspace in the text at this point. |
| Insert a newline in the text at this point. |
| Insert a carriage return in the text at this point. |
| 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 spaceNon-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.
The single underscore, _, MAY be used as an unnamed variable or parameter
wherever Java’s unnamed-variable syntax applies — for a local variable,
pattern-match binding, or lambda parameter whose value is never read. It
signals to the reader that the value is deliberately unused.
Where a name composed of ordinary words needs converting to one of this standard’s camel-case forms, follow this procedure: first transliterate the name to plain ASCII (eg. "Müller" to "Mueller") and remove any apostrophes (eg. "Müller’s algorithm" to "Muellers algorithm"); then split the result into words at space and punctuation boundaries; then lowercase the entire result; then uppercase the first letter of each word — every word for UpperCamelCase, every word except the first for lowerCamelCase.
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
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.
Records SHOULD follow the same naming conventions as classes: UpperCamelCase,
typically a singular noun or noun phrase describing the data they hold, eg.
Point, OrderLine.
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
Tappended, 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.
- Break before non-assignment operators as well as operator-like symbols such
as the dot separator (
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) {}An empty statement — a stray ; with no effect — SHOULD be avoided. This
is a different, and always erroneous, construct from an empty block: an
empty block ({}) is sometimes intentional, per the guidance above, but a
bare ; is never intentional, and is usually a typo — for example, an
accidental ; immediately after an if condition, which silently turns
the following block into an unconditional statement.
if (isValid(input)); // The trailing `;` makes this an empty statement —
{ // the block below always runs, regardless of
process(input); // whether `isValid(input)` is true.
}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, andwhilekeywords 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, andcatchfrom the opening parenthesis that follows them on the same line. - To separate reserved words such as
elseandcatchfrom 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 enhancedforstatement. - The arrow in a lambda expression:
(String str) → str.length()
- The ampersand in a conjunctive type bound:
- 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]
Horizontal alignment more generally — adding variable amounts of whitespace so that a token lines up with a token on a nearby line — is permitted but never REQUIRED, and once broken by a subsequent edit it does not need to be restored. Reformatting a line that an otherwise-unrelated change did not itself touch, purely to preserve alignment, is discouraged: the realignment produces a diff noise that obscures the actual change.
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.
Grouping parentheses
Optional grouping parentheses SHOULD be kept unless both the author and a reviewer agree there is no reasonable chance the expression could be misread without them. It is not reasonable to assume that every reader has Java’s operator precedence table memorized — grouping parentheses that remove that burden are worth their small cost in verbosity.
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.
Inner assignment — assigning a variable as a side effect inside a larger
expression, eg. String s = Integer.toString(i = 2); — SHOULD be avoided.
An assignment SHOULD occur as its own top-level statement, so a reader
scanning an expression for its value is not also scanning it for side
effects. The one common exception is the header of a for loop, where an
assignment as part of the loop’s initialization or update clause is
idiomatic.
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:
- Class (
static) variables - Instance variables
- Constructors
- 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.)
Every constructor in a public or protected class SHOULD be explicit — an
implicit default constructor SHOULD NOT be relied upon in a class-like
construct that forms part of a public API. Declaring the constructor
explicitly forces a deliberate decision about its access level, and prevents
a class from becoming publicly instantiable by accident.
A utility class — one containing only static methods and constants, per
Class and interface names — SHOULD NOT have a public constructor.
Declare its constructor private (or protected if the class is intended
to be subclassed) instead. Instantiating a utility class serves no purpose,
and a forgotten default constructor leaves it publicly instantiable by
accident, which the explicit-constructor rule above does not by itself
prevent — an explicit public constructor is still public.
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) {}Avoid catching java.lang.Exception, java.lang.Error, or
java.lang.RuntimeException directly. Catching one of these broad types
risks silently swallowing a failure the catch block was never written to
handle — a NullPointerException or an OutOfMemoryError, for example —
that should be allowed to propagate rather than being absorbed by a handler
meant for a narrower, expected failure. Catch the most specific exception
type the code can meaningfully recover from instead.
Object.finalize MUST NOT be overridden. Finalization is unreliable, and
Java has scheduled the finalization mechanism for removal.
A class that overrides equals() MUST also override hashCode(). The
equals()/hashCode() contract requires that two objects considered equal
by equals() produce the same hash code; violating this breaks the
class’s behavior in any hash-based collection (HashMap, HashSet, and
similar), where an object may become unfindable even by a key that
equals() says is identical to the one it was stored under.
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).
Switch expressions
Java also supports new-style, arrow-labeled switch syntax, which SHOULD be
preferred over the old-style case … :/break/fall-through form above for
new code. Each label is followed by → and either a single expression, a
block, or a throw statement — never a break — and there is no
fall-through between labels.
String result = switch (input) {
case 1, 2 -> "one or two";
case 3 -> "three";
default -> "large number";
};A switch expression — one whose result is assigned or returned, as in the
example above — MUST use the new-style arrow syntax; the old-style
case … : form is not permitted there. A switch statement, which does not
produce a value, MAY use either form, but arrow syntax is RECOMMENDED for
consistency and to avoid unintended fall-through.
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.
Text blocks
A multi-line string literal SHOULD use a text block (""" … """) rather than
concatenated single-line string literals joined with \n or +.
String html = """
<html>
<body>
<p>Hello, world.</p>
</body>
</html>
""";The opening """ MUST be on its own line, and the closing """ MUST also
be on its own line, indented to match the indentation of the text block’s
content. Each line of text within the block MUST be indented at least as
much as the delimiters. Unlike an ordinary string literal, a text block’s
contents MAY exceed the standard’s column limit, since reflowing the text
would change the string’s value.
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[]
Strings
== and != MUST NOT be used to compare String values. Use .equals()
instead: == compares reference identity — whether two variables point to
the same String object — not content, so two String`s holding the same
characters can compare unequal with `== if they were not interned to the
same object.
String a = new String("foo");
String b = new String("foo");
a.equals(b); // true
a == b; // falseNumeric precision
float and double SHOULD NOT be used for values that require exact
decimal precision, such as currency amounts. Binary floating-point cannot
represent most decimal fractions exactly, so arithmetic on float/double
values accumulates small rounding errors that compound over repeated
calculations. Use BigDecimal instead for monetary and other
precision-sensitive decimal values.
Nullability
A null reference lets a variable point to nothing, which makes it possible to
define an uninitialized reference-typed variable. Every mainstream language
carries some form of this concept, under different names: None in Python,
null in Java, JavaScript, Kotlin, and Scala, NULL in PHP, and nil in
Ruby and Swift. C.A.R. Hoare, who introduced the null reference into ALGOL W
in 1965, later called it his "billion-dollar mistake" for the errors,
vulnerabilities, and system crashes it has caused since.
Java has neither non-nullable types nor null-safe operators, which makes a
NullPointerException easy to trigger by accident. Consider the following
method chain:
var baz = getFoo().getBar().getBaz();
Every method in this chain can potentially return null, and calling a
method on that null result raises a NullPointerException. Avoiding this
safely means checking every intermediate return value, which becomes
verbose quickly:
var foo = getFoo();
var bar = null;
var baz = null;
if (foo != null) {
bar = foo.getBar();
if (bar != null) {
baz = bar.getBaz();
}
}Java 8 introduced
Optional,
a wrapper type around a value that may be absent, comparable to Maybe or
Option in other languages. This standard RECOMMENDS Optional as Java’s
nullability mechanism: a method SHOULD return type X where X cannot be
null, and Optional<X> where it can. Applying this to the getFoo,
getBar, and getBaz methods above allows the method chain to be
refactored in a null-safe way, using flatMap to chain the calls:
final var baz = getFoo().flatMap(Foo::getBar)
.flatMap(Bar::getBaz)
.orElse(null);A method whose return type is not Optional<X> MUST NOT return null
under any circumstance. Where a meaningful value genuinely cannot be
produced, throw an exception instead of returning null from a
non-Optional return type — Optional<X> is how this standard expects an
absent return value to be communicated.
Optional does not eliminate NullPointerException`s entirely: Java gives
no guarantee that an `Optional reference itself is not null. Optional
SHOULD NOT be used for method input parameters — it exists to communicate an
absent return value, not to express an optional argument.
A number of annotation libraries exist to make nullability explicit in code
that does not use Optional, each providing its own @NonNull/@Nullable
(or similarly named) annotations:
Library | Package |
|---|---|
| |
| |
| |
| |
| |
| |
| |
|
None of these libraries are bulletproof — each works differently, and none
can guarantee null-safety the way a language with built-in non-nullable
types can — but where Optional does not fit, an annotation library is the
best mechanism Java offers.
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 temporarily.
//SHOULD be avoided for this purpose in production code, where it SHOULD be temporary only, since a//-commented- out line is easy for static analysis tooling to detect and reject before the code is merged. - For short end-of-line comments that decode or explain a value assigned, returned, or printed by the statement.
Commented-out code SHOULD NOT be committed to version control, which already tracks the code’s history — a comment is not needed to preserve it.
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. Comments MUST NOT be enclosed in boxes drawn with asterisks or other characters.
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 restate what the code already says, since a redundant comment is likely to fall out of date as the code evolves without the comment being updated to match. The frequency of comments in a piece of code is sometimes itself a symptom of poor code quality: where the urge to add a comment arises, consider first whether rewriting the code to make it clearer would remove the need for the comment altogether.
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.
A Javadoc comment MUST immediately precede the declaration it documents, and MUST NOT be positioned inside a method or constructor body: the Javadoc tool associates a doc comment with the first declaration that follows it, so a Javadoc comment placed inside a body documents nothing.
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. Information about a class, interface, variable, or method that is not appropriate for the doc comment SHOULD instead go in an implementation comment immediately after the declaration. A long, discursive description or a usage example SHOULD generally be excluded from Javadoc too, and placed instead in a README or other out-of-band document that the Javadoc references — Javadoc is consulted in passing, at the point of use, and is a poor home for material a reader needs to sit down and read.
Javadoc SHOULD be used to document every visible top-level class-like
construct and every visible member — visibility here meaning any class,
interface, record, field, or method that is not private, plus every
component of a public or protected record. Javadoc MAY be skipped for a
member that is "simple" and "obvious" — such as a trivial getter or setter —
only where there is truly nothing else worthwhile to say about it, and MAY
also be skipped for a method that overrides a supertype method which is
already documented, since the supertype method’s documentation is inherited.
A private member is not required to carry Javadoc, but SHOULD where it is
complex, or where it is called from multiple places. Where a private method
is called from only one place, its documentation MAY instead live in the
calling method’s Javadoc.
Where a class or method’s contract is not obviously thread-safe from its name and signature, its Javadoc MUST state the thread-safety guarantees it makes. Absent an explicit statement, a caller is entitled to assume the class is not thread-safe. This is a documentation obligation only; the design of thread-safe classes themselves is covered by TS-7: Code design.
Javadoc serves two distinct purposes, and a comment SHOULD NOT mix them: an API specification is a contract describing behavior a caller can rely on, independent of any one implementation — boundary conditions, parameter ranges, corner cases, and what is deliberately left unspecified. A programming guide is illustrative material — usage examples, term definitions, conceptual overviews, and notes on known bugs or workarounds. Where a Javadoc comment needs to say something implementation-specific rather than part of the general contract, that material belongs in its own paragraph, introduced with a lead-in such as "Implementation-Specific:".
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 opening / MUST be on its own line, each
subsequent line MUST begin with a aligned under the second character of
the opening /, and the closing / MUST be on its own line, aligned the
same way. For a top-level class or interface, the opening / is not
indented and the aligned on subsequent lines has one space before it; for
a member, the opening / is indented four spaces and the aligned on
subsequent lines has five spaces before it, matching the member’s own
indentation level.
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: a noun phrase or verb phrase, not a complete sentence, but capitalized and punctuated as if it were one. It SHOULD NOT be a detailed description.
A method’s summary fragment SHOULD start with a third-person descriptive verb
("Gets the label", not "Get the label"). A class, interface, or field
description SHOULD instead state what the thing represents ("A button
label"), avoiding phrasing such as "This class…" or "This method…". Where the
description refers to the object the Javadoc is attached to, use "this"
rather than "the" ("Gets the toolkit for this component"). Where it refers to
a method in its general form, omit parentheses and argument types ("the
add method"); include argument types only when referring to one specific
overload ("the add(int, Object) method").
Javadoc MUST distinguish overloaded methods and constructors from each other — each overload’s summary fragment SHOULD identify what makes it distinct, rather than repeating the same description across every overload.
The Javadoc tool does not document anonymous inner classes. Any content that would document one SHOULD instead be written in the doc comment of its enclosing class.
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:
@paramfor method parameters@returnfor the return value of a method@throwsfor exceptions thrown by a method@deprecatedto 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, which MUST
NOT be empty. When the description is long, it SHOULD be wrapped with
continuation lines indented four spaces from the position of the @ symbol.
A blank line (containing only the aligned leading asterisk) SHOULD appear
before the group of block tags, separating them from the preceding prose.
A block tag’s description is tag content, not prose, and follows a different register from the rest of this section’s full-sentence rule: it SHOULD be a single sentence fragment, without a capitalized first word or a terminal period. Columns MAY be aligned across a run of block tags, but this is a cosmetic choice, not a requirement, and SHOULD NOT be maintained by reformatting lines that a change did not otherwise touch.
@param and @return are REQUIRED — for every parameter and for every
non-void method, respectively — even where their purpose seems obvious from
the signature alone. @param takes the parameter name, not its data type,
and MUST NOT wrap that name in <code>. Where a method has more than one
@param tag, they MUST appear in the same order as the parameters are
declared. Where @return describes a collection, it SHOULD state the type of
element the collection contains.
@throws SHOULD cover every checked exception a method can throw, and any
unchecked exception a caller might reasonably want to catch — except
NullPointerException, which SHOULD NOT be documented. Errors SHOULD NOT be
documented. An unchecked exception tied to a specific implementation SHOULD
be documented by its general supertype rather than the concrete subtype (eg.
IndexOutOfBoundsException, not ArrayIndexOutOfBoundsException). The
@throws tag is distinct from the method’s throws clause: including an
unchecked exception in the throws clause itself, rather than only in
@throws, is poor practice. Where a method has more than one @throws tag,
they MUST appear in alphabetical order by exception name.
@deprecated MUST be paired with the @Deprecated annotation — the
annotation produces a compiler warning, while the tag documents the reason.
Its first sentence SHOULD state when the API was deprecated and what to use
instead, linked with {@link} or @see; where there is no replacement, it
SHOULD state "No replacement".
The {@link} inline tag SHOULD be used for an automatic, checked link to
another class, method, or field. The @see block tag is an alternative,
used for a cross-reference that stands apart from the description rather
than inline within it. Where more than one @see tag is present, they
SHOULD be ordered by their proximity to the documented element — nearest
first.
{@return} MAY be used in place of a @return block tag, to generate the
summary fragment and the return-value description from a single inline tag.
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. */
The @since, @author, and @version tags SHOULD NOT be used. The version
control system already tracks when and by whom a declaration was introduced,
and these tags are of more use to library maintainers publishing a versioned
API than to application development.
Where a class implements Serializable and its Javadoc uses the
serialization-specific tags @serial, @serialField, or @serialData,
those tags MUST come after @see and before @deprecated. Combined with the
order given above and the tags this standard disallows, the full canonical
block-tag order — for reference, though @author, @version, and @since
SHOULD NOT appear per the rule above — is: @author, @version, @param,
@return, @throws, @see, @since, @serial/@serialField/
@serialData, @deprecated.
Where a Javadoc comment refers to a Java keyword, a package name, a class,
method, interface, or field name, an argument name, or a code example, that
text MUST be wrapped in <code> tags. Curly (smart) quotes MUST NOT appear
in Javadoc text; use straight quotes throughout. Latin abbreviations SHOULD
be avoided in favor of their English equivalents: "also known as" rather
than "aka", "that is" rather than "i.e.", "for example" rather than "e.g.",
and "in other words" or "namely" rather than "viz.".
Not every Javadoc comment needs to meet the full formatting bar above. Where Javadoc is written beyond what the scope rules above require, following the conventions in this section is RECOMMENDED but not REQUIRED.
Package-level Javadoc
Package-level Javadoc is written in the file-level doc comment of a
package-info.java file (see Special source files). It SHOULD follow a
three-part structure: a summary sentence describing the package’s purpose, a
"Package Specification" section for any formal contract the package as a
whole makes, and a "Related Documentation" section linking out to other
relevant material.
Images in Javadoc
Where an image is needed in Javadoc, it MUST be placed in a doc-files
subdirectory of the package it documents, and named <class>-<n>.gif,
matching the class it illustrates and a sequence number.
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… */
// …
}import org.springframework.data.jpa.repository.JpaRepository;
public interface UserRepository extends JpaRepository<User, Long> {
// …
}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
- Google Java Style Guide
- Oracle: Code Conventions for the Java Programming Language
- Oracle: The Java Tutorials
- Oracle: How to Write Doc Comments for the Javadoc Tool — The source for the Javadoc content and formatting guidance in Javadoc.
- Oracle: Code Conventions for the Java Programming Language — Comments — The source for the implementation-comment and Javadoc formatting guidance in Javadoc.