Abstract: Javadoc specifies the details of our methods using special tags such as @param and @return. After Java 5, we did not see new standard Javadoc tags for 13 years. The hope was that annotations would replace the chaos of doclets. But tags have not disappeared. In this newsletter, we examine several new tags to improve our Javadoc experience.
Welcome to the 308th edition of The Java(tm) Specialists' Newsletter, sent from the beautiful Island of Crete. We are getting ready for JCrete 2023, which means exploring the many incredible restaurants and beaches that we might want to visit with our fellow JCretans. On the Tuesday, we get up early and head off to the Balos and Elafonissi beaches. We usually get there before any other tourists. Both of these beaches were listed as among the top 3 of Crete by Vogue. My top tip for any amazing place on Crete - either visit in spring or go very early.
One of our most popular live courses is Refactoring to Streams. We have taught it dozens of times in the last two years. We felt it was time to create a self-paced version for you, that you can study in the comfort of your home, at a pace that is best for your learning style :-) The course is a ton of fun, as we take stodgy old code and transform it into a thing of beauty using streams and lambdas. Since we code in Java 17, we get to explore some of the newer features such as records and the teeing collector. The price is $197 (including local taxes) and you can grab the course here.
javaspecialists.teachable.com: Please visit our new self-study course catalog to see how you can upskill your Java knowledge.
Before we had annotations (yes, those days existed), we would create custom tags and add them to Javadoc. We would then extend the Javadoc tool using Doclets to process these specific tags. One issue used to be that Javadoc was non-reentrant, so my hack was to launch it in its own class loader. There was even a tool called XDoclet to make the Javadoc tag parsing easier. After the Java 5 release, the use case for extending Javadoc with custom tags went away. Instead, we could write annotations and then create a visitor to walk over our abstract syntax tree.
I've thus been ignoring the Javadoc tags for a while. However, whilst writing
the previous newsletter, I noticed
something I had not seen before. One of the methods had what looked like a
printf()
formatting String inside a tag called
{@value}
. In fact, I had also not noticed the {@value}
tag before. This led me to the Documentation
Comment Specification for the Standard Doclet (JDK 20), which lists
all the standard tags for Javadoc. Turns out, {@value}
has been
around since JDK 1.4! However, it is seldom used in the JDK.
If we scan through the JDK source tree, we find that up until recently,
{@value}
was only used with ConstantDescs#INIT_NAME
and ConstantDescs#CLASS_INIT_NAME
, for example in
java.lang.StackTraceElement#getMethodName()
:
* the appropriate <i>special method name</i>, {@value ConstantDescs#INIT_NAME} * or {@value ConstantDescs#CLASS_INIT_NAME}, as per Section {@jvms 3.9} * of <cite>The Java Virtual Machine Specification</cite>.
The values were then inlined into the Javadoc HTML:
"the appropriate special method name, <init>
or
<clinit>
, as per Section 3.9
of The Java Virtual Machine Specification."
Note that two of the custom tags that the JDK Javadocs uses are {@jvms} and {@jls}, which link to the Java Virtual Machine Specification and the Java Language Specification respectively. We find these hundreds of times in the JDK, linking the code to the specifications. Other interesting custom tags are @implNote, @implSpec, and @apiNote.
Let's go back to the @value
tag. This is defined as an inline
tag, as opposed to a block tag. This means it needs to be surrounded by
curly braces and appear inside text, as we saw in the example above
{@value ConstantDescs#INIT_NAME}
. In Java 20, they added the
ability to format the value, by inserting a format as a String. We see this
in java.lang.reflect.AccessFlag#MANDATED
,
which formats the Javadoc as:
/** * The access flag {@code ACC_MANDATED} with a mask value of * <code>{@value "0x%04x" Modifier#MANDATED}</code>. */ MANDATED(Modifier.MANDATED, false, Location.SET_MANDATED_9, new Function<ClassFileFormatVersion, Set<Location>>() { /* *snip* */ })
The Javadoc output looks like this: "The access flag ACC_MANDATED
with
a mask value of 0x8000
."
Here is another example with my own class:
public class FormattingInlinedValues { public static final String FIRST_NAME = "Heinz"; private static final String MIDDLE_NAME = "Max"; protected static final String LAST_NAME = "Kabutz"; public static final int AGE = 51; public static final double HEIGHT = 1.8824213; static final boolean THIN = false; /** * {@return the details of the author} This includes the * {@value "FIRST_NAME=%s" #FIRST_NAME}, the {@value * "LAST_NAME=%s" #LAST_NAME}, the {@value "AGE=0x%04x" * #AGE} in hexadecimal, and the {@value "HEIGHT=%.2fm" * #HEIGHT}. We will leave out the property of {@value * "THIN=%B" #THIN} and the {@value "MIDDLE_NAME=%s" * #MIDDLE_NAME} as not relevant to writing skills. */ public String toString() { return "%s %s of age 0x%04x is %.2fm tall".formatted(FIRST_NAME, LAST_NAME, AGE, HEIGHT); } public static void main(String... args) { System.out.println(new FormattingInlinedValues()); } }
This time, the Javadoc comment looks like this: "Returns the details of the author. This includes the FIRST_NAME=Heinz, the LAST_NAME=Kabutz, the AGE=0x0033 in hexadecimal, and the HEIGHT=1,88m. We will leave out the property of THIN=FALSE and the MIDDLE_NAME=Max as not relevant to writing skills."
Javadoc added hyperlinks to the accessible members (protected and public),
but not the package access and private
such as
THIN
and MIDDLE_NAME
.
Even with this new formatting, I doubt that @value
will be
used a lot. The use case is a tad obscure.
The super observant reader would have noticed a slight change in how I wrote
the @return
tag. Instead of the usual block tag, I wrote it at
the top of the Javadoc as an inline tag. This new feature was added in Java
16, and solves a huge annoyance with Javadocs. We frequently see code like
the isSynthetic()
method in java.lang.Class
. This
is how it used to look:
// Java 16 public class Class<T> { /** * Returns {@code true} if and only if this class has * the synthetic modifier bit set. * * @return {@code true} if and only if this class has * the synthetic modifier bit set * @jls 13.1 The Form of a Binary * @jvms 4.1 The {@code ClassFile} Structure * @since 1.5 */ public boolean isSynthetic() { return (getModifiers() & SYNTHETIC) != 0; } }
But instead of repeating ourselves, we can now use the {@return ...} inline
tag. This is isSynthetic()
in Java 17:
// Java 17 public class Class<T> { /** * {@return {@code true} if and only if this class has * the synthetic modifier bit set} * * @jls 13.1 The Form of a Binary * @jvms 4.1 The {@code ClassFile} Structure * @since 1.5 */ public boolean isSynthetic() { return (getModifiers() & SYNTHETIC) != 0; } }
The inline {@return}
is super popular in the JDK and has been
used over 1000 times already. I can see why. It always felt smelly to copy
and paste the text between the start of the method and the @return
block tag. Now we can avoid that.
Besides formatted @value
and inlined {@return}
, we
also have three other new tags since Java 11. The tag @snippet
was
added in Java 18 to make it easier to add demo code to our Javadoc. It is a
fairly complex and powerful feature, and I will delay exploring that until a
future newsletter.
Then we have the tag @spec
, added in Java 20, which links to a
formal specification to describe the method. This is used mostly to refer to
networking and unicode specifications. For example, see InetAddress.getByName(String)
,
which links to the specifications RFC 3330 and RFC 2373.
Lastly we have {@systemProperty}
, added in Java 12,
which is also used surprisingly often in the JDK. There are over a 100
system properties defined like this. Some of these are legacy properties,
such as java.home
and line.separator
, whereas
others are new, such as jdk.virtualThreadScheduler.parallelism
.
We can see an example in the Implementation Note of java.lang.Thread.
Besides documentation, this tag does not seem to do much, except to make
system properties easier to find.
To be honest, I didn't expect this rabbit hole to be so deep when I began
my descent. All I started with is "0x%04x" and we learned a whole bunch.
I hope you enjoyed it and that you'll be able to tidy up your Javadoc
@return
comments, and perhaps inline a @value
or
two where it makes sense.
King 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.