Java Style Guidelines (Draft, v6)
Andreas Lundblad, December 2015Introduction
This is a set of style guidelines for for JDK Release Projects in the OpenJDK Community. Other OpenJDK Projects, and projects outside of OpenJDK, are welcome to adopt these guidelines as they see fit.
Motivation
Code that looks familiar is easier to understand and therefore also easier to review, debug and maintain. To ensure that code looks familiar to all developers on the project it’s important to agree on a common set of style guidelines.
This document provides guidelines for low level coding practices such as how to indent code and how to name types and variables. Many of the stylistic choices are subjective and different developers may have different opinions about them. Keep in mind however, that having a consistent style is more important than to satisfy each individual developers preference.
Guiding Principles
The guidelines in this document strive to maximize,
- Correctness
- Readability
- Maintainability
- Debuggability
- Consistency
- Aesthetics
While this document covers a lot of ground, it should be noted that no style guide can answer all questions for us, and developers will always need to use good judgment towards the end of producing code that is correct, readable, maintainable, debuggable, consistently formatted, and aesthetically pleasing.
Examples in this document are non-normative; While they intend to illustrate correct way of formatting the code, there may be other ways to correctly format the code. This is a general principle: There may be several ways to format the code, all adhering to the guidelines in this document.
Tool support is nice, but ultimately each IDE and style checking tool can handle different sets of rules, and support for rules that can’t be handled today might be added in future versions. So, whether a rule plays well with tools or not can be a factor, but it’s secondary to the above principles.
Java Source Files
This section concerns ordinary .java files only. Rules do not necessarily apply to other source
files in the project such as .jasm, .sh or .gmk.
LF, ASCII value 10) and
not for instance CR or CR+LF.
.java extension, even for files that only contain a package private class. This does not apply
to files that do not contain any class declarations, such as package-info.java.
7-bit ASCII reduces errors due to confusion of characters since there are no invisible spaces, characters that look like minus signs but are really dashes, etc. It also ensures packages and classes are named in such way that the corresponding directories and source files are portable across different filesystems.
Agreeing on a common line delimiter character is important since different operating systems have
different defaults. Editing a file on Windows that was originally written on Linux, may cause all
LF to be saved back as CR+LF. This creates an unnecessarily big
patches and may not display correctly in the text editor it was originally written in. A single line
feed character is default for Unix-like systems and supported by all common text editors and IDEs.
Trailing white space is nothing but unnecessary cruft. It’s easy to remove and agreeing on doing so consistently minimizes diffs.
Not using the name of the class as filename can be confusing. Also, unless the file is given explicitly to the compiler, the class it contains may not be resolved correctly.
Special Characters
LF the only allowed white space character is Space (ASCII value 32). Note that
this implies that other white space characters (in, for instance, string and character literals) must be
written in escaped form.\', \", \\, \t, \b, \r,
\f, and \n should be preferred over corresponding octal (e.g. \047)
or Unicode (e.g. \u0027) escaped characters.
Having any white space character but space and LF in the source code can be a source of
confusion.
The short forms (e.g. \t) are commonly used and easier to recognize than the corresponding
longer forms (\011, \u0009).
Formatting
.java source file should be structured as follows:
- The copyright notice
- Package declaration
- Import statements
- Class declaration
Copyright notice
/*
* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
or
/*
* Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
where the first year is the year the file was created and the second year is the year the file was last
edited.
For questions regarding copyright or license notices, please contact iris.clark@oracle.com.
Package declaration
Import statements
- …primarily by non-static / static with non-static imports first.
-
…secondarily by package origin according to the following order
javapackagesjavaxpackages- external packages (e.g.
org.xml) - internal packages (e.g.
com.sun)
- …tertiary by package and class identifier in lexicographical order
Wildcard Imports
Wildcard imports makes it unclear what actually needs to be imported.
Having more than one wildcard import makes the code fragile since adding a new class in one of the imported packages can introduce a name clash.
An unused import gives a false impression of a dependency. Also, many IDEs list such import statements as warnings which clutters the list of problems.
Class Structure
The recommended order of class members is the following:
- Fields
- Constructors
- Factory methods
- Other Methods
Order of Constructors and Overloaded Methods
public HashSet() {
this(DEFAULT_INITIAL_CAPACITY);
}
public HashSet(int capacity) {
this(capacity, DEFAULT_LOAD_FACTOR);
}
public HashSet(int capacity, double loadFactor) {
…
}
// Overloaded methods should not be split apart
void logValue(int i) {
log("Int: %d", i);
}
void setValue(int i) {
val = i;
}
void logValue(double d) {
log("Double: %.2d", d);
}
void setValue(double d) {
val = d;
}
This order puts the most generally applicable versions first. Also, making sure delegation is always done downwards in the file makes the code easier to follow.
Modifiers
- Access modifier (
public/private/protected) abstractstaticfinaltransientvolatiledefaultsynchronizednativestrictfp
Writing out modifiers where they are implicit clutters the code and learning which modifiers are implicit where is easy.
Although method parameters should typically not be mutated, consistently marking all parameters in every
methods as final is an exaggeration.
Making fields immutable where possible is good programming practice. Refer to Effective Java, Item 15: Minimize Mutability for details.
Braces
Braces are recommended even where the language makes them optional, such as single-line if and loop bodies.
- If a block spans more than one line (including comments) it must have braces.
- If one of the blocks in a if / else statement has braces, the other block must too.
- If the block comes last in an enclosing block, it must have braces.
else, catch and the while keyword in
do…while loops go on the same line as the closing brace of the preceding
block.
void method() {
…
}
try {
something();
} catch (AnException e) {
…
}
for (int[] row : matrix) {
for (int val : row) {
sum += val;
}
}
// Wrong placement of opening brace
void method()
{
…
}
// Newline in front of catch should be avoided
try {
something();
}
catch (AnException e) {
…
}
// Braces should be used
if (flag)
// Restore x
x = 1;
// Use braces if block comes last in enclosing block
// to avoid accidentally indenting the closing brace.
for (int[] row : matrix) {
for (int val : row)
sum += val;
}
Putting opening braces on the end of the line (as opposed to on a line of its own) is a long standing Java convention. This style is also suitable for Java, considering that it’s common to have small blocks (in for instance anonymous classes and lambda expressions) and having opening braces on a separate line creates an unnecessary amount of white space in such situations.
Omitting braces is error prone and can lead to mistakes in the indentation and hard to detect bugs.
Short Forms
enum Response { YES, NO, MAYBE }
public boolean isReference() { return true; }
public boolean getResult() { int value = getValue(); return value < 0 ? 0 : value; }
for (int i = 0; i < size; i++) { sum += data[i]; }
Indentation
case lines should be indented with four spaces, and statements within the case should be
indented with another four spaces.
Existing code that follows the old style of not indenting case lines (see Don’ts
example below) is acceptable to leave as is.
switch (var) {
case TWO:
setChoice("two");
break;
case THREE:
setChoice("three");
break;
default:
throw new IllegalArgumentException();
}
switch (var) {
case TWO:
setChoice("two");
break;
case THREE:
setChoice("three");
break;
default:
throw new IllegalArgumentException();
}
By using spaces for indentation, problems regarding different default settings for tab stops in various editors are avoided.
Wrapping Lines
Source code and comments should generally not exceed 80 characters per line and rarely if ever exceed 100 characters per line, including indentation.
The character limit must be judged on a case by case basis. What really matters is the semantical “density” and readability of the line. Making lines gratuitously long makes them hard to read; similarly, making “heroic attempts” to fit them into 80 columns can also make them hard to read. The flexibility outlined here aims to enable developers to avoid these extremes, not to maximize use of monitor real-estate.
// Ok even though it might exceed max line width when indented.
Error e = isTypeParam
? Errors.InvalidRepeatableAnnotationNotApplicable(targetContainerType, on)
: Errors.InvalidRepeatableAnnotationNotApplicableInContext(targetContainerType));
String pretty = Stream.of(args)
.map(Argument::prettyPrint)
.collectors(joining(", "));
// Too strict interpretation of max line width. Readability suffers.
Error e = isTypeParam
? Errors.InvalidRepeatableAnnotationNotApplicable(
targetContainerType, on)
: Errors.InvalidRepeatableAnnotationNotApplicableInContext(
targetContainerType);
// Should be wrapped even though it fits within the character limit
String pretty = Stream.of(args).map(Argument::prettyPrint).collectors(joining(", "));
aMethodCall(withMany(arguments, that, needs),
to(be, (wrapped - to) * avoid / veryLong - lines));
aMethodCall(withMany(arguments, that, needs), to(be, (wrapped
- to) * avoid / veryLong - lines));
i += j;
j += k;
if (condition) {
return expression;
}
i += j; j += k;
if (condition) { return expression; }
- Variant 1: With 8 extra spaces relative to the indentation of the previous line.
- Variant 2: With 8 extra spaces relative to the starting column of the wrapped expression.
- Variant 3: Aligned with previous sibling expression (as long as it is clear that it’s a continuation line)
- Variant 4: Aligned with previous method call in a chained expression.
// Variant 1
int anInteger = aMethod(that, takes,
a, lengthy, list, of, arguments);
// Variant 2
int anInteger = that * (is + computed) / using
+ a * complex - expression;
// Variant 3
int anInteger = aMethod(thatTakes,
aLongList,
ofArguments);
// Variant 4
int anInteger = IntStream.of(numbers)
.map(Math::sqrt)
.sum();
// Mixing of wrapping variants (unless there
// is a logical grouping of arguments)
int anInteger = aMethod(that,
takes,
a, lengthy, list,
of, arguments);
// Don't align with sibling expression if the continuation
// line can be confused with a block indentation
if (somePredicate() ||
someOtherPredicate()) {
System.out.println("Avoid");
}
Wrapping Class Declarations
extends and/or implements keywords.
public class MyGenericClass<T, S>
extends HashMap<T, S>
implements Comparable<T> {
…
}
public class AnotherClass<K, R> implements Collector<T extends K,
Set<? extends R>,
List<R>> {
…
}
public class MyGenericClass<T> implements Comparable<T>,
Predicate<T> {
…
}
Wrapping Method Declarations
int someMethod(String aString,
List<Integer> aList,
Map<String, String> aMap,
int anInt,
long aLong,
Set<Number> aSet,
double aDouble) {
…
}
int someMethod(String aString, List<Integer> aList,
Map<String, String> aMap, int anInt, long aLong,
double aDouble, long aLong) {
…
}
int someMethod(String aString,
List<Map<Integer, StringBuffer>> aListOfMaps,
Map<String, String> aMap)
throws IllegalArgumentException {
…
}
int someMethod(String aString, List<Integer> aList,
Map<String, String> aMap, int anInt)
throws IllegalArgumentException {
…
}
// If aligning the parameters vertically, don't put two
// parameters on one line
int someMethod(String aString,
List<Integer> aList,
Map<String, String> aMap,
int anInt, long aLong,
Set<Number> aSet,
double aDouble) {
…
}
int someMethod(String aString,
List<Map<Integer, StringBuffer>> aListOfMaps,
Map<String, String> aMap) throws InterruptedException {
…
}
int someMethod(String aString,
List<Integer> aList,
Map<String, String> aMap)
throws IllegalArgumentException {
…
}
Wrapping Expressions
. in chained method calls.methodCall(a * simple - formula,
some + complex - formula * spanning
+ multiple - lines * may
+ look - as * follows);
popupMsg("Inbox notification: You have "
+ newMsgs + " new messages");
persons.stream()
.map(Person::getName)
.forEach(System.out::println);
// Arity unclear
methodCall(a * simple - formula,
some + complex - formula * spanning +
multiple - lines * should + not *
look - as * follows);
// Looks like two arguments
popupMsg("Inbox notification: You have " +
newMsgs + " new messages");
persons.stream().
map(Person::getName).
forEach(System.out::println);
Whitespace
Vertical Whitespace
- Copyright notice
- Package declaration
- Class declarations
- Constructors
- Methods
- Static initializers
- Instance initializers
…and may be used to separate logical groups of
- import statements
- fields
- statements
Horizontal Whitespace
- To separate keywords from neighboring opening or closing brackets and braces
- Before and after all binary operators and operator like symbols such as arrows in lambda expressions and the colon in enhanced for loops (but not before the colon of a label)
- After
//that starts a comment. - After commas separating arguments and semicolons separating the parts of a for loop.
- After the closing parenthesis of a cast.
int someInt;
String myString;
char aChar;
long sixtyfourFlags;
if (isFlagSet(GO)) {
…
}
IntUnaryOperator inc = x -> x + 1;
init: {
…
}
int someInt;
String myString;
char aChar;
long sixtyfourFlags;
if( isFlagSet( GO ) ) {
…
}
IntUnaryOperator inc = x->x + 1;
init : {
…
}
The improvement in readability when aligning variable names is negligible compared to the efforts needed to keep them aligned as the code evolves. Realigning all variables when one of the types change also causes unnecessarily complicated patches to review.
Variable Declarations
String[] args) and not on the variable
(String args[]).Annotations
@Deprecated
@Override
public void foo() {
…
}
@Deprecated @Override
public void foo() {
…
}
addListener(new Listener() {
// Ignored events
@Override public void event1() { }
@Override public void event2() { }
@Override public void event3() { }
// Important event
@Override
public void event4() {
…
}
});
@Override @Deprecated public void foo() {
…
}
@Override @Deprecated
@SafeVarargs
public void foo() {
…
}
Lambda Expressions
Method references should generally be preferred over lambda expressions.
For bound instance method references, or methods with arity greater than one, a lambda expression may be easier to understand and therefore preferred. Especially if the behavior of the method is not clear from the context.
Runnable r = () -> System.out.println("Hello World");
Supplier<String> c = () -> "Hello World";
// Collection::contains is a simple unary method and its behavior is
// clear from the context. A method reference is preferred here.
appendFilter(goodStrings::contains);
// A lambda expression is more readable in this case
// (cf. corresponding example in Don'ts section)
trackTemperature((time, temp) -> tempMap.put(time, temp));
Function<Person, String> nameFunc = p -> p.getFirstName() + " " + p.getLastName();
class Util {
private static String getCapitalizedFirstName(Person p) {
String first = p.getFirstName();
char initial = Character.toUpperCase(first.charAt(0));
return initial + first.substring(1);
}
static void printAllPersons(List<Person> persons) {
persons.stream()
.map(Util::getCapitalizedFirstName)
.forEach(System.out::println);
}
}
Runnable r = () -> { System.out.println("Hello World"); };
Supplier<String> s = () -> { return "Hello World"; };
// A lambda expression is not needed here
appendFilter(s -> goodStrings.contains(s));
// Map::put is a binary function, and it's not clear from context what type
// of argument trackTemperature accepts. A lambda expression is better here.
trackTemperature(tempMap::put);
// Unnecessary parameter type
Function<Person, String> nameFunc = (Person p) -> p.getFirstName() + " " + p.getLastName();
class Util {
static void printAllPersons(List<Person> persons) {
persons.stream()
.map(p -> {
String first = p.getFirstName();
char initial = Character.toTitleCase(first.charAt(0));
return initial + first.substring(1);
})
.forEach(System.out::println);
}
}
Redundant Parentheses
return flag ? "yes" : "no";
String cmp = (flag1 != flag2) ? "not equal" : "equal";
return (flag ? "yes" : "no");
Literals
long literals should use the upper case letter L suffix.A-F.long l = 5432L;
int i = 0x123 + 0xABC;
byte b = 0b1010;
float f1 = 1 / 5432f;
float f2 = 0.123e4f;
double d1 = 1 / 5432d; // or 1 / 5432.0
double d2 = 0x1.3p2;
long l = 5432l;
int i = 0X123 + 0xabc;
byte b = 0B1010;
float f1 = 1 / 5432F;
float f2 = 0.123E4f;
double d1 = 1 / 5432D;
double d2 = 0x1.3P2;
Lower case L resembles a 1 in many monospace fonts which means that the literal 5432l can be
confused with 54321. Using upper case L suffix avoids this. The lowercase
0x, 0b, e, p, f, and d
characters are easier to spot in a long sequence of digits, and they avoid confusion with the
hexadecimal digits A-F.
Javadoc
This section only covers basic Javadoc formatting. For a complete reference refer to How to Write Doc Comments for the Javadoc Tool.
{@code …} and {@link …} etc) over
corresponding HTML tags (<code>…</code>,
<a href="…">…</a> etc).
<p> to separate paragraphs (closing </p> tags are not needed
and should not be used)/** A short javadoc comment */
/**
* …
*
* <blockquote>{@code
* List<String> names;
* }</blockquote>
*/
/** put on single line instead
*/
/**
* The <String> below may interfere with the HTML!
*
* <blockquote><pre>
* List<String> names;
* </pre></blockquote>
*/
Naming
Package Names
java.lang.annotation and not java.lang.annotations.
Class, Interface and Enum Names
class EmptyCell {
…
}
class RunningMode {
…
}
interface Expandable {
…
}
class XmlParser {
…
}
class Empty {
…
}
class Running {
…
}
class Expandable {
…
}
// Abbreviation should be formatted as 'Xml'
class XMLParser {
…
}
Method Names
public void expand() {
…
}
public boolean isExpanding() {
…
}
public State getState() {
…
}
public boolean expanding() {
…
}
public State GetState() {
…
}
public int get_index() {
…
}
Variables
int currentIndex;
boolean dataAvailable;
int current_index;
boolean DataAvailable;
Type Variables
K and V for keys and
values in maps or R for a function return type) use that, otherwise use T.
_) to separate words.interface SpecialMap<K, V> extends Map<K, V> {
…
}
class GraphMapper<SRC_VERTEX, SRC_EDGE, DST_VERTEX, DST_EDGE> {
…
}
interface SpecialMap<Key, Value> extends Map<Key, Value> {
…
}
class GraphMapper<S, T, U, V> {
…
}
Constants
_) to separate words.public static final int BUFFER_SIZE = 1024;
enum ApplicationMode { RUNNING, PAUSED, TERMINATED }
public final List<String> CURRENT_WORDS = new ArrayList<>();
enum ApplicationMode { Running, Paused, Terminated }
Programming Practices
The focus of the guidelines in this document is on style. General guidelines on best programming practices, use of design patterns, how to structure programs etc is thus out of scope. A few “low level” practices that are easy to pin down is however good to agree upon.
@Override where it is possible to do so.TODO” comments. If the missing code doesn’t affect
correctness or performance, skip the comment, otherwise file an issue for it.// fall through” comment.Commenting Code
//) otherwise use multiline comments
(/* … */).When to reformat code
Cleaning up code that’s unrelated to the patch may…
- Complicate the review of the patch in which case correctness may suffer
- Run the risk of breaking existing code
- Have a downstream impact, e.g. affect ports to other versions.
- Trigger an unnecessary debate (perhaps the original formatting was intentional).