Laden...
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
Java Specialists Superpack '23 Our entire Java Specialists Training in One Huge BundleLaden...
Laden...