Structuring, ordering, and formatting Java source code files.
GJSG 2 Source file basics is normative, without amendment.
GJSG 3 Source file structure is normative, with the amendments below.
package
statementThough not explicitly stated in the source file structure shown in the GJSG, it is implied that there will always be a package statement. In fact, this is a strict requirement of this bootcamp: All classes (including enums) and interfaces must use the package
statement (with a corresponding directory structure) to place the class or interface in a package other than the default (unnamed) package.
GJSG 3.3.1 No wildcard imports:
Wildcard imports, static or otherwise, are not used.
We permit just one exception to this rule: In testing frameworks such as JUnit, it is common to have a large number of static
methods within a class, providing a variety of specialized assertions. A wildcard import static
statement (e.g., import static org.junit.jupiter.api.Assertions.*;
) is permitted in test classes that make use of these frameworks. However, when practical, a command like IntelliJ IDEA’s Code/Optimize Imports should be used to resolve the wildcard imports into non-wildcard forms.
GJSG 3.4.2 Ordering of class contents:
The order you choose for the members and initializers of your class can have a great effect on learnability. However, there’s no single correct recipe for how to do it; different classes may order their contents in different ways.
What is important is that each class uses some logical order, which its maintainer could explain if asked. For example, new methods are not just habitually added to the end of the class, as that would yield “chronological by date added” ordering, which is not a logical ordering.
We agree with the above. However, we require more predictable structure in the ordering of class members:
The order of class members must follow this general sequence:
static final
fieldsstatic
(but non-final
) fieldsfinal
(but non-static
) fieldsstatic
, non-final
) fieldsstatic
initializer blocksstatic
initializer blocksThis still does not fully dictate the order of members within each of the above groups. There’s no single correct way of ordering these contents; this may even vary from class to class. However, there are strict rules that must be followed; one is stated in GJSG 3.4.2.1 Overloads: never split; two more follow below.
All getters and setters must be grouped together.
Accessors and mutators that follow the JavaBeans naming conventions (aka getters and setters) must be grouped together. That is, if a class has multiple inferrable properties that are accessible for reading via get
Property
(for a non-boolean
-valued property) or is
Property
(for a boolean
-valued property) methods, and/or accessible for writing via set
Property
methods, the accessor and mutator methods for all such properties must be grouped together.
Never split accessor/mutator pairs.
When a class has a pair of methods that follow the JavaBeans naming convention for accessors & mutators for some inferable property name, these methods must appear sequentially, with no other code between them (not even private members).
GJSG 4 Formatting is normative, with the amendments below.
GJSG 4.6.1 Vertical whitespace:
Multiple consecutive blank lines are permitted, but discouraged, and never required.
We constrain the use of vertical whitespace further with these rules:
Consecutive blank lines are discouraged but permitted between members of a class, but the number of blank lines used must be consistent or predictable.
Consecutive blank lines are not permitted inside the body of an initializer, constructor, or method.
GJSG 4.7 Grouping parentheses: recommended:
Optional grouping parentheses are omitted only when author and reviewer agree that there is no reasonable chance the code will be misinterpreted without them, nor would they have made the code easier to read. It is not reasonable to assume that every reader has the entire Java operator precedence table memorized.
To the above, we add 2 strict rules:
Though the compiler treats parentheses around a single lambda parameter as optional, they are required in this bootcamp.
If the conditional (Boolean) operand of a ternary expression contains 1 or more binary operators, other than the .
member access operator, the entire conditional operand must be enclosed in parentheses. For example, take the these 2 statements that include ternary expressions:
int a = (c >= 0) ? c : -c;
String s = t.isEmpty() ? null : t;
In the first, the conditional operand includes the binary operator >=
; thus, we enclose the entire conditional operand (c >= 0
) in parentheses. In the second, while there are parentheses for the isEmpty
method invocation, the only operator in the conditional operand is the member access operator .
; thus, parentheses around the conditional operand are optional, but not required.
switch
statementsGJSG 4.8.4.3 The default
case is present:
Each switch statement includes a
default
statement group, even if it contains no code.Exception: A switch statement for an
enum
type may omit thedefault
statement group, if it includes explicit cases covering all possible values of that type. This enables IDEs or other static analysis tools to issue a warning if any cases were missed.
The above is further constrained: when a default
is present (which, as noted, must be the case, except when the case
values are all of the enumerated values of an enum
), it must be the last statement group in the switch
. (In fact, there are use cases for a default
statement group that is not the last statement group in a switch
; however, in our opinion, the potential for confusion in this practice far outweighs its utility.)