The German version of this article has been published in JavaSPEKTRUM 6/2022 and can be downloaded and read as a PDF file.
Abstract
Javadoc has proven its value as a source-code oriented API documentation solution over the last two decades. However, using its documentation comments requires some detailed knowledge. Those who know about the crucial Javadoc subtleties feel more confident, can create more consistent documentation, and thus improve software quality in several respects.
Introduction
Javadoc exists since the early days of Java and has since been a loyal companion not only to the JDK itself, but also to various third-party libraries. Assuming a minimum of discipline, the immediate proximity of the documentation comments to the source code makes it much less likely that these two will drift apart. At the very least, the proximity to the source code makes it much more difficult to reach the state of the dreaded “wiki rot”: outdated, overly formal, useless, annoying, or simply non-existent pages regarding the software architecture on the company’s wiki, or even worse as Word files on SharePoint.
Of course, documentation is a large topic. There are different types of documentation, which mainly differ in their target audiences and viewpoints. Unfortunately, it is not possible to cover these within the scope of this article, but if you want to learn more about them (which I highly recommend!), a search for Gernot Starke or Stefan Zörner will certainly find the people who are probably best known in the German-speaking countries, including their books and courses. If you want a good first overview, I recommend [Zoe22].
Of course, it would be presumptuous to claim that Javadoc was the jack of all trades with respect to documentation solutions. For the purpose of this article, I will only consider software developers as authors and as readers of technical documentation, i.e., no end users, no POs, no sales people, and no managers. However, my experience (and hopefully that of the software developing readers) shows that Javadoc can cover a significant part of the needs in developer-to-developer communication. So if you are still on a greenfield in terms of documentation: Javadoc would be an ideal start.
Rationale for (Source Code) Documentation
The many reasons for comprehensive documentation of in-house developed software are theoretically obvious and are propagated in unison in all popular development literature. However, no work seems to be as disliked and characterized as “unnecessary” as that of documenting.
Let’s not fool ourselves: documentation debts—i.e., no, little, or outdated documentation—are technical debts. Good documentation forms the basis for further analysis and improvements to the software architecture [Lil20]. Without documentation, this crucial foundation falls away.
Software is usually read far more often than it is written [Ull22]. I personally call this “multiplier”: If I invest 30 additional minutes in a good class or method description during development, but in return can save 20 additional employees tedious and error-prone reverse engineering work (each requiring more than 30 minutes of effort) over the next 10 years, then the calculation clearly adds up. Not to mention the many (expensive) programming errors which can so be avoided at best, because the documentation already explicitly points out necessary preconditions, side effects, or other stumbling blocks.
Until now, we have also always benefited from detailed (Javadoc) APIs of the libraries we use: the JDK itself, JUnit, the Spring framework, Google Guava, Apache Commons, or in other languages Angular, NumPy, TensorFlow, and many more. With all these popular libraries, it is quite natural to solely follow their API documentation. None of those library developers would ever have thought of saying: “The source code is the best documentation, that’s why we don’t publish any API documentation.” If they had lived it that way, the library would not have become popular. It’s as simple as that.
So why should your own software be subject to a different principle? After all, a human being is not a compiler. Anyone who expects their employees to mentally “decompile” their own code in a Sisyphean task, just because they are too lazy or unable to document it appropriately by themselves, is behaving antisocially by definition. Not to mention the horrendous costs that arise for the employer (or the customer), because the reverse engineering work has to be repeated with each new employee and after oblivion has occurred (usually a few days to a few weeks).
Regarding code as the primary “documentation” source also contradicts the fundamental principles of object-oriented programming: data encapsulation and the principle of secrecy. One of the large achievements of software development in the last decades is the division into public
and private
sections and associated clear interface
s and thus “contracts” towards the users. In addition, there are various safety nets which prevent (accidental) overwriting of data or inadmissible method calls. Why should these principles, which apply at (technical) development and runtime, not also apply at (human) read and analysis time?
At this point, there usually comes the first objection that with Clean Code or Test-Driven Development (TDD) or Extreme Programming (XP)—you name it—as they practice it in-house, the source code is self-speaking and clear enough, and therefore there is no reason to comment or document anything beyond that. From my observations, however, I have never been able to confirm this.
There are indeed various aspects that cannot be expressed with source code alone: preconditions, invariants, postconditions, side effects, thread safety, possibilities and behavior with inheritance, idempotency, statefulness of statelessness, permissions and behavior with transactions, justifications for design choices (why this way and not another?), integration and behavior within the big picture, usage examples or intended use cases, references to other modules, known bugs, open construction sites (TODOs), and much more. If classes or methods cannot be documented easily, then they are either too large, too complicated, or the developers themselves did not understand them. All three reasons strongly suggest to reconsider the design again.
Also the Agile Manifesto (“Working software over comprehensive documentation”) is no excuse to abandon documentation. (This would have been too good, wouldn’t it?) Because the sentence goes on: “[…] while there is value in the items on the right, we value the items on the left more.” [Manifesto] So there never was and never will be any mention of the fact that agile working methods like Scrum do no longer need documentation! Of course, I would also prefer working software over extensive documentation. Just as I would prefer “water over food” on a desert expedition. But this does not mean that I can abstain from food for the rest of my life.
In fact, in agile software development, the focus is on communication: communication with stakeholders, communication within teams, communication between teams, and distribution (i.e., communication) of knowledge. And documentation supports this kind of communication [Zoe22]. If you document, you communicate; and vice versa.
Basic Syntax
Javadocs are placed in the form of documentation comments (doc comments) directly in front of the respective modules, packages, classes, interfaces, constructors, methods, enum values, and attributes. These block comments are introduced with /**
. Note the two asterisks (“stars”); a block comment starting with /**
is always a Javadoc comment (though possibly an invalid one if placed incorrectly), whereas ordinary block comments are prefixed with /*
(i.e., with only one asterisk). Subsequent comment lines do not necessarily have to start with *
, although I have rarely if ever seen them being omitted. Even the Javadoc generators functions of common IDEs automatically add asterisks at the line beginnings.
A Javadoc comment consists of two parts: a main description, whose content developers are free to define, and a subsequent section with block tags, which describe parameters, return values, exceptions, and various other properties in a systematic notation (see the following section). The main description can theoretically be omitted (although not recommended), but all necessary block tags must be listed, otherwise there will be a warning or even an error when generating the documentation.
The commando javadoc
, which is part of the JDK, generates a well-structured and navigable HTML 5 documentation from the source code and the corresponding Javadoc comments. Other output formats besides HTML could be created using doclets (from third party vendors, or self-programmed), although I personally don’t see much sense in forgoing the HTML variant that has been established for so many years.
The javadoc
generator provides a plethora of options in the form of call parameters, which, however, mostly only refer to details and special cases and are therefore not discussed any further in this article. Moreover, classic Java IDEs such as IntelliJ IDEA or Eclipse already provide dialog boxes for generating Javadoc API documentation where the common options can be set. If you still want to get an overview of all options, please refer to [javadocCommand].
The first sentence of the main description has a special meaning: It serves as a summary description within the generated class, constructor, method, and other overviews. It should therefore always be formulated with appropriate care. A classic mistake that can happen is the accidental premature termination of the sentence due to a period and a following whitespace, as for example with abbreviations (e.g.
, etc.
) or with ordinal numbers (1.
, 2.
). To avoid such problems, it is recommended to encode the critical parts using the inline tag {@literal}
(here: {@literal e.g.}
) or—as it is possible since Java 10—to wrap the whole summary description in {@summary text}
. I find the new {@summary}
variant very appealing and will therefore use it exclusively in my examples.
All subsequent paragraphs of the main description should be supplied with HTML <p>
tags. In general, Javadoc comments allow HTML embedding. At the same time, one should follow the principle that doc comments should be similarly readable in both source code and generated documentation, which usually advocates against excessive use of fancy HTML formatting.
Select Block and Inline Tags
Javadoc knows two types of tags: block tags of the form @identifier content
, each of which must be placed by itself at the beginning of a line, and inline tags of the form {@identifier content}
(i.e., with braces), which may be used within other descriptions.
Table 1 shows some select block and inline tags. For a complete and very good description of all tags, please refer to the official Documentation Comment Specification for the Standard Doclet (JDK 19) [CommentSpec]. In the table, I mainly omitted tags concerning serialization and the module system (since Java 11). I also omitted @author
and @version
, because today source code is usually written by several people, and keeping track of version numbers in each class has become practically redundant due to the use of version control systems like Git. Meanwhile, the Javadoc generator only adopts @author
and @version
when setting corresponding call parameters, and they are disabled by default [javadocCommand].
Documentation Tag | Description |
---|---|
General Block Tags | |
@deprecated text |
Marks the documented element as deprecated. Should always be used together with the @Deprecated source code annotation (since Java 5). The text should refer to a replacement. |
@hidden |
Selectively removes the documented element from the generated HTML documentation (since Java 9). |
@param parameter description |
Describes the corresponding constructor or method parameter. |
@return description |
Describes the return value of the documented method. |
@since text |
Indicates since which version the documented element exists. |
@throws exception description |
Describes the corresponding exception. See separate section on this topic. |
General Inline Tags | |
{@code text} |
Allows inserting short, single-line sections of code (since Java 5). Is equivalent to <code>{@literal text}</code> . Angle brackets (< , > ) in the text are not interpreted as HTML entities. See also separate section on this topic. |
{@index word/phrase description} |
Manually adds a word or phrase (in quotes) to the generated index (since Java 9). |
{@literal text} |
Like @code , just without code formatting (since Java 5). |
{@summary text} |
Uses the enclosed text as a summary in the generated documentation (since Java 10). Must be placed at the beginning of the main description. |
{@systemProperty name} |
Denotes a system property. |
Inheritance | |
{@inheritDoc} |
Copies the corresponding documentation comment from the inherited class or interface. See separate section on this topic. |
Linking and Embedding Code | |
{@link reference label} |
Creates a link to reference with the label label . Here reference has the general form package.class#member . |
{@linkplain reference label} |
Like @link , just without code formatting. |
@see reference label |
Creates a link to reference with the label label in the section “See also” of the generated HTML documentation. |
@snippet |
Introduces a code snippet (since Java 18). See [CommentSpec] and [SnippetsGuide] for more details. |
Listing 1 shows some of the mentioned block and inline tags as a comprehensive example.
Exceptions
As is generally known, Java distinguishes between checked exceptions and unchecked exceptions. Checked exceptions must be caught, handled, or thrown, whereas unchecked exceptions can be—casually speaking—ignored in the code.
Exceptions are described in Javadoc using @throws
tags. @exception
is a synonym for this, but should not be used (anymore). With a complete documentation of all call parameters (via @param
) and exceptions (via @throws
), the preconditions of a constructor or method—and thus the “contract” between caller and callee—can be effectively specified.
By convention, only checked exceptions should be declared in the throws
clause of a constructor and method signature. In the corresponding Javadoc, however, unchecked exceptions should also be documented using @throws
if they are within the responsibility of the caller (which is typically the case for NullPointerException
s and IllegalArgumentException
s of the corresponding parameters). This convention also helps developers to immediately identify whether an exception is a checked exception (listed in both throws
and @throws
) or an unchecked exception (listed only in @throws
) [BloItem74]. Listing 1 also shows an example use of the @throws
tags.
Inheritance
Javadoc comments can be inherited by subclasses or interfaces. The Javadoc generator automatically links overriding or implementing methods to the super method, together with the remark “Overrides” or “Specified by”, respectively.
Missing main descriptions or missing @param
, @return
, or @throws
tags of overriding or implementing methods are automatically copied from the corresponding super methods. For @throws
, however, this only applies to declared exceptions, which, according to what was said in the previous section, usually excludes unchecked exceptions.
The {@inheritDoc}
inline tag can be used to insert the corresponding main description or the corresponding @param
, @return
, or @throws
comment of the parent method at this exact position. Usually, text is written around {@inheritDoc}
, so the corresponding comment of the parent method is literally embedded.
However, these rules only apply to method comments, not to constructors, attributes, or inner classes. The inheritance rules are described in more detail in [CommentSpec]. Listing 2 shows a short example of a subclass of the class from Listing 1. Figure 1 shows a screenshot of the corresponding generated Javadoc HTML.
Linguistic Matters
Javadoc comments for interface descriptions should preferably be written in English, since (newly) hired software developers are getting more and more international. However, I would not implement this rule too rigidly. In German-speaking countries, a locally based medium-sized metal construction company with a development department may still have good reasons to prefer documentation in German, in contrast to an internationally oriented bank or insurance company. In particular, if the software contains technical logic that is difficult to translate into other languages, I recommend following the principle: better good German than bad English. Because the latter really doesn’t help anyone, neither the author nor the reader.
Those who decide to use English should be aware that American English and British English are basically two different languages. It is recommended—if not already done—to strive for a company-wide guideline as early as possible as to which variety of the English language should be used internally and externally. Experience shows that this is not just an insignificant detail, but a fundamental and far-reaching decision.
By convention, the description of a @param
and @return
tag should correspond to a noun phrase. Such a phrase (without verb) has a nominal head, starts with lower case (unless the noun itself is capitalized), and ends without a period, unless followed by other phrases.
The description of a @throws
-Tags tag starts with the lowercase word “if” and then describes—with a verb—under which circumstances the exception can occur. Again, it does not end with a period unless followed by something else.
The first and thus summarizing sentence (which strictly speaking is not a complete sentence) of a class, interface, and attribute description should also be a nominal phrase, but this time with capitalization at the beginning and a final period at the end. The latter also has technical reasons, as explained in detail above.
However, the summary description of a constructor and method should always be a verb phrase, i.e., a “sentence” with a verb but without a noun. Also here, it starts with capitalization and ends with a period.
All mentioned (partial) sentences should always be stated in the third person singular (e.g., “Returns the duration […].”) and not as an imperative (command form, e.g., “Return the duration […].”). The latter should be reserved for pure source code comments, where it is “commanded” what the following code section should do.
All these small but crucial linguistic subtleties are described in [BloItem56] and can be seen again in Listing 1.
Linking and Embedding Code
Within descriptions, the inline tags {@link reference label}
and {@linkplain reference label}
can be used to insert links to other types and methods. The two inline tags only differ in the resulting formatting: {@link}
displays the link in code formatting, {@linkplain}
in normal font.
The reference
, which is analogous to the href
attribute of an HTML <a>
tag, follows the general scheme package.class#member
. For example, a reference to the equals
method of the class String
with the label “equals” would look like this:
See {@link String#equals(Object) equals} for more details.
The comment above could also be implemented using the block tag @see
. In the generated HTML documentation, it then appears as a separate section with the heading “See also”:
@see String#equals(Object) equals
Very short, single-line code sections can preferably be included with {@code text}
. HTML entities such as angle brackets are ignored. Only when using curly braces, one has to make sure that the number of opening braces in the code is the same as the number of closing braces. {@literal text}
is the counterpart to {@code}
, just without code formatting.
For longer code sections, it was previously necessary to resort to preformatted HTML blocks of the form <pre>{@code ...}</pre>
. With the implementation of JEP 413 in Java 18—so still quite new—there is a new block tag @snippet
[JEP413]. It allows both the direct embedding and the external linking of code snippets, adjustable indentation, highlighting within the source code, automatic text substitutions (also with regular expressions), the specification of individual regions, and lots more. A discussion of the extensive range of functions would go beyond the scope of this article. The reader is therefore referred to [SnippetGuide] for a comprehensive introduction including examples.
Conclusion
It is probably not very effective to “force” every software developer in the company to do the same amount of documentation work. Each person has their professional strengths and weaknesses. Documentation that is produced only reluctantly or is of poor quality will also be of little use to the readers.
Nevertheless, I think that effective documentation can be learned the same way as programming. All it takes is the will, a concept, and an objective benchmark (“teacher” or book) to orient oneself by. It is always surprising that developers and POs continue their education in databases, agile methods, the innovations in Java 17 (LTS) or the use of the Amazon Cloud (AWS), but approach the topic of documentation only with improvisation or shrugs.
I would therefore like to propose a solution which I have already presented in one form or the other in my previous articles. It is probably more efficient if there are a few proven experts within the development team, each of which is responsible for a specific topic (here: documentation). Those who like to document well will do the entire development department—and thus the company—a big favor. Either way, the point “Javadoc created or updated” should be a fix part of every code review.
In [Zoe22], Stefan Zörner even goes one step further and proposes the role of a “doctator” who, among other things, has and creates an overview of the documentation, integrates the process of documenting into both the human and technical workflow (build pipeline), supports the teams in the actual documentation work, and monitors the currency and consistency of the content. If no one can be found in-house, it would also be a viable option to initially engange an external person for this role.
I hope that this article has raised awareness of the topic of documentation in general and, with regard to Javadoc in particular, has contributed to more background information, detailed knowledge and thus increased consistency and quality.
Literature and Links
- [BloItem56]
- J. Bloch, Effective Java, Item 56: Write doc comments for all exposed API elements, 3rd Edition, Addison-Wesley, 2018
- [BloItem74]
- J. Bloch, Effective Java, Item 74: Document all exceptions thrown by each method, 3rd Edition, Addison-Wesley, 2018
- [CommentSpec]
- Documentation Comment Specification for the Standard Doclet (JDK 19), docs.oracle.com/en/java/javase/19/docs/specs/javadoc/doc-comment-spec.html
- [javadocCommand]
- The javadoc Command, docs.oracle.com/en/java/javase/19/docs/specs/man/javadoc.html
- [JEP413]
- OpenJDK, JEP 413: Code Snippets in Java API Documentation, openjdk.java.net/jeps/413
- [Lil20]
- C. Lilienthal, Langlebige Software-Architekturen, 3. Auflage, dpunkt.verlag, 2020
- [Manifesto]
- Manifesto for Agile Software Development, agilemanifesto.org
- [SnippetsGuide]
- Programmer’s Guide to Snippets, docs.oracle.com/en/java/javase/18/code-snippet/index.html
- [Ull22]
- C. Ullenboom, Java ist auch eine Insel, 16. Auflage, Rheinwerk Verlag, 2022
- [Zoe22]
- S. Zörner, Softwarearchitekturen dokumentieren und kommunizieren, 3. Auflage, Hanser, 2022
Shortlink to this blog post: link.simplexacode.ch/gh322023.05
Amy Grunert
3 Jul 2023Hi there would you mind stating which blog platform you’re
using? I’m looking to start my own blog soon but I’m having a difficult time selecting between BlogEngine/Wordpress/B2evolution and Drupal.
The reason I ask is because your layout seems different then most blogs and I’m looking for something
completely unique. P.S Sorry for getting off-topic but I had
to ask!
Christian Heitzmann
4 Jul 2023It’s WordPress.