Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to document (simple) preconditions of a Java method?

Tags:

java

javadoc

It is often the case that a method imposes constraints on its arguments that cannot be described by the type system. For example, a method might require that some argument be non-null, or some int-typed argument be positive. There might also be more complex preconditions, for example that a certain method was called before, or that a certain object is in some state. What is the best way to document this in Javadoc?

For example, suppose I have the following public library function, where the argument cannot be negative:

public void foo(int bar) {
    if (bar < 0) {
        throw new IllegalArgumentException("Negative bars cannot be food.");
    }
    ...
} 

I want to document this in such a way that it "stands out" from the rest of the documentation text so that documentation readers know immediately where they have to look. Currently, I do this by adding throws clauses to the Javadoc:

/**
 * Foos a bar.
 * @param bar  the bar to be food
 * @throws IllegalArgumentException  if bar is negative
 */
public void foo(int bar) {
    ...

However, this introduces the throwing of the exception into the specification of the method. Now, library users might depend on this behavior in their code. So if I want to change the method in a next version in such a way that also negative parameters are allowed, I might break clients' code.

Are there any best practices to document things like this in Javadoc? I have thought of:

  • Describing in the documentation text that the method has undefined behavior if the argument is negative. However, this does not really stand out, so it might be missed by a lot of library users.
  • Using annotations (public void foo(@NonNegative int bar)). However, for this a standard set of annotations would be ideal, and this standard set does not appear to exist.
like image 319
Hoopje Avatar asked Nov 03 '14 22:11

Hoopje


People also ask

What is a precondition of a method in Java?

A precondition is a condition that must be true for your method code to work, for example the assumption that the parameters have values and are not null. The methods could check for these preconditions, but they do not have to. The precondition is what the method expects in order to do its job properly.

How do you write pre and post conditions?

It is common to place the precondition/postcondition pair in a comment immediately after the function's parameter list. // Precondition: x >= 0. // Postcondition: The square root of x has // been written to the standard output.

Do All methods have preconditions?

Sometimes, your methods may not have preconditions. It may be that a client does not need to do or know anything at all to successfully call your method. In those cases, it's ok to not mention preconditions at all. However, every method should have a postcondition.

How do you create a method document in Java?

From the main menu, select Tools | Generate JavaDoc. In the dialog that opens, select a scope — a set of files or directories for which you want to generate the reference, and set the output directory where the generated documentation will be placed.


2 Answers

You can create custom javadoc tags, i.e. @pre @inv and @post for precondition, invariant and postcondition.

Further, Joshua Bloch argues in Effective Java Second Edition:

The doc comment should enumerate all of the method's preconditions, which are the things that have to be true in order for a client to invoke it, and its postconditions Typically, preconditions are described implicitly by the @throws tags for unchecked exceptions; each unchecked exception corresponds to a precondition violation. Also, preconditions can be specified along with the affected parameters in their @param tags.

Examples:

/**
 * @param index index of element to return; must be non-negative and less
 *              than the size of this list
 * @throws IndexOutOfBoundsException if the index is out of range
 *                                   ({@code index < 0 || index >= this.size()})
 */

Note, that every exceptions begins with if, followed by a clause describing the conditions under which the exception is thrown. (precondition) This is often described with arithmetic expressions.

like image 172
Matthias Holdorf Avatar answered Sep 20 '22 14:09

Matthias Holdorf


You seem hesitant to rely on your API's Javadocs to provide exactly that: documentation for your API. While I agree some developers will invariably ignore its warnings, I think historically Javadocs have been entirely adequate in providing sufficient guidance on how to correctly use an API. You can go crazy creating all kinds of custom Annotations, but in the end people will still implement your API incorrectly at times.

If you did want to go even further beyond what you already have there, you could also implement self-documenting naming conventions wherever practical. For example:

/**
 * Foos a positive bar.
 * @param positiveBar  the non-zero,non-negative bar to be food
 * @throws IllegalArgumentException  if bar is zero or negative
 */
public void foo(int positiveBar) {
    ...

Lastly, although your question is about how to document these constraints and not handle them, I will say to not underestimate the value of IllegalArgumentException. This is precisely what it should be used for and engineers should not be afraid to throw this exception to indicate a programming error. Developers aren't going to get far without reading the docs when their implementation doesn't run.

like image 36
Jeffrey Mixon Avatar answered Sep 21 '22 14:09

Jeffrey Mixon