Abstract: Should we write "public abstract static class" or "public static abstract class"? And should fields be "final static private" or "private static final"? In this newsletter we explore the canonical order of modifiers in Java.
Welcome to the 293rd edition of The Java(tm) Specialists' Newsletter. Most mornings after the school drop, I get to grab a coffee at what must be one of the most efficient coffee bars anywhere. Voula spots me parking my Suzuki Jimny outside, and immediately gets to work grinding my arabica coffee beans. By the time my mask is on and I am waddling into her shop, she has already poured my "diplo espresso, sketo, choris kapaki" (double espresso, black without sugar, without the plastic lid). Yes, I have occasionally spilled my coffee, but it irks me to stick a plastic lid on something I will consume in the next few minutes anyway. The coffee is already rung up on her POS and after a few friendly words, I'm on my way. Most mornings go off without a hitch, but unfortunately Voula occasionally gets days off. On those days we have a hearty exchange trying to explain that yes, I do want a hot coffee, not cold, and no, I do not want sugar, I'm sure of that, and no, I also don't want the plastic lid but thank you so much for asking.
javaspecialists.teachable.com: Please visit our new self-study course catalog to see how you can upskill your Java knowledge.
I was reading some Java code the other day and began to
notice that the order of the modifiers looked peculiar.
Some fields were defined as final
private
then others as final static
private
and then others as the more typical
private static final
. I am so used to
reading one particular sequence of modifiers, that this
looked strangely messy. Perhaps my German Ordnung genes were
kicking in? Or was there a canonical order that was
preferred and which I have used for so long that I only
notice it when it is not followed?
After digging around in IntelliJ IDEA's code analyzer, I found this inspection: Java -> Code style issues -> Missorted modifiers. It claimed that it would report declarations whose modifiers were not in the canonical preferred order (as stated in the Java Language Specification). Thus there was some order that was apparently preferred, but what was that order?
After searching in the Java Language Specification for a while, I found JLS section 8.3.1, which states that "If two or more (distinct) field modifiers appear in a field declaration, it is customary, though not required, that they appear in the order consistent with that shown above in the production for FieldModifier. Aha, so what are all the possible FieldModifiers?
FieldModifier: (one of) Annotation public protected private static final transient volatile
Thus the annotation should come first, and then the other modifiers in that order. Our code will compile even if we do not follow this canonical order, but it's a bit like leaving the toilet seat up in a shared house. As we will see, the OpenJDK follows this canonical order quite consistently.
Methods have a similar preferred order, defined in JLS section 8.4.3:
MethodModifier: (one of) Annotation public protected private abstract static final synchronized native strictfp
Constructor is a bit easier, because only in the case of an annotation can we have more than one modifier, defined in JLS section 8.8.3:
ConstructorModifier: (one of) Annotation public protected private
The class also has quite a few modifiers, especially since sealed classes were added. The most common mistake is to write static before abstract. Again, we can find the recommended order in JLS section 8.1.1:
ClassModifier: (one of) Annotation public protected private abstract static final sealed non-sealed strictfp
It is not too difficult to remember most of them. Annotations always come first. Then we have public/protected/private. Next up is abstract, if applicable. Then static and final. The rest is too rare to bother memorizing.
I sent IntelliJ IDEA off to look through the OpenJDK code. It found only 135 variations of this canonical modifier order. That is surprisingly few, considering that the OpenJDK has over 10 millions lines of Java code. The most common deviation was when annotations were not the first modifier, which happened 96/135 times, over 71%. Next up were 18 "static abstract" instead of the more canonical "abstract static". Then 12 public/protected/private after other modifiers. The 9 remaining places had mixed up final / static / native / transient and volatile.
After the OpenJDK, I decided to run the analyzer over the sample code for my Dynamic Proxies in Java book. I found 10 missorted modifiers, always "final static" instead of "static final". Oops. I also ran it over Jetty 10.x and in their 622k LOC did not find any missorted modifiers. Well done Jetty!
I then inspected Spring Framework with its 1.2m LOC. There we found 159 warnings, of which 79 were writing static abstract instead of abstract static, 46 were the annotations not the first modifier, 28 was final static instead of static final, the mistake that I made too and then only 6 had public/protected/final not immediately after the annotation.
It seems that the module-info.java file also follows a
canonical order. I found only one module-info.java file in
the OpenJDK that deviated from that slightly. Here is the
order that I believe we should use. Always start with
requires
, so that anyone looking at
our module-info.java file immediately sees what modules we depend
on. Next we list
all requires transitive
, followed by
requires static
. We then show the
packages that our module exports
generally followed by those exports that are to a specific
module. Next we list all the packages that we allow deep
reflection on via opens
, preferably
to
a specific module. Lastly we have
uses
and then
provides
for the
ServiceLoader
. The order can be seen in
JLS Module Directive:
[open] module some.module.name { requires ... requires transitive ... requires static ... exports ... exports ... to ... ... ... opens ... opens ... to ... ... ... uses ... provides ... with ... ... ... }
Also, the class names in uses
and
provides
should be fully qualified,
thus import
statements should not be
used.
Kind regards
Heinz
We are always happy to receive comments from our readers. Feel free to send me a comment via email or discuss the newsletter in our JavaSpecialists Slack Channel (Get an invite here)
We deliver relevant courses, by top Java developers to produce more resourceful and efficient programmers within their organisations.