Comments #

A comment is text in your code that the compiler completely ignores — it produces no bytecode, affects no performance, and doesn’t exist in the running program. Its purpose is purely for humans: explaining design decisions, warning about unintuitive behavior, and documenting public APIs. Java provides three types of comments, each with a different purpose. The most important — and most misused — is Javadoc, Java’s built-in documentation system that can be turned into HTML pages just like Java’s own official documentation. This article covers when and how to use each type of comment, including anti-patterns that actually make code harder to understand.

Single-Line Comments #

A single-line comment starts with // and runs to the end of the line. This is the most frequently used comment type for short, inline explanations.

// Maximum login attempt limit
int maxAttempts = 3;

int count = 0;
count++; // increment after each failed attempt

// Use an epsilon to avoid floating-point errors
double epsilon = 1e-9;
if (Math.abs(a - b) < epsilon) {
    // Treat as equal if the difference is tiny
}

When to Use Single-Line Comments #

Single-line comments are most useful for explaining why something is done, not what is done — because good code already explains the what by itself:

// ANTI-PATTERN: commenting things that are already obvious from the code
int i = 0;          // set i to 0
i++;                // add 1 to i
list.clear();       // clear the list

// CORRECT: comment the reason (why), not the mechanism (what)
int attempts = 0;
attempts++;         // on each failure, the counter rises before the limit check

list.clear();       // reset state before processing the next batch
                    // don't remove this — needed to avoid stale data

// Timeout reduced by 500ms because of network overhead in the staging environment
int timeoutMs = 4500;

Block Comments #

Block comments wrap text between /* and */. They can span one or many lines, and are useful for explanations too long for a single line.

/*
 * This algorithm uses a sliding window approach to find the
 * longest substring without repeating characters. Time complexity is O(n)
 * because each character is processed at most twice.
 */
public int longestUniqueSubstring(String s) {
    Map<Character, Integer> positions = new HashMap<>();
    int max = 0, left = 0;

    for (int right = 0; right < s.length(); right++) {
        char c = s.charAt(right);
        if (positions.containsKey(c) && positions.get(c) >= left) {
            left = positions.get(c) + 1;
        }
        positions.put(c, right);
        max = Math.max(max, right - left + 1);
    }
    return max;
}

Block Comments for Temporarily Disabling Code #

Block comments are often used during debugging to quickly disable a section of code:

/*
// Old code — temporarily disabled during the migration to API v2
Response resp = apiV1.sendRequest(payload);
processResponseV1(resp);
*/

// New code
Response resp = apiV2.sendRequest(payload);
processResponseV2(resp);

Block comments cannot be nested. If the text you want to comment out already contains */ inside it, the compiler thinks the comment ends there and produces a compile error. This is a common trap when disabling a block of code that already contains another block comment.

/* This fails because there's a */ in the middle
   and the compiler thinks the comment ends there */

Documentation Comments (Javadoc) #

Javadoc is the most powerful and most important feature of Java’s comment system. Javadoc comments are wrapped in /** and */ and placed directly above public class, interface, method, or field declarations. The javadoc tool then processes these comments into HTML documentation — the same format as the official Java documentation at docs.oracle.com.

flowchart LR
    A["Source Code .java\nwith /**...*/ comments"] -->|"javadoc -d docs src/"| B["HTML Documentation"]
    B --> C["index.html\nclass-use/\npackage-summary.html\n..."]
    C --> D(["\nBrowser\n(like docs.oracle.com)"])

    style A color:#000,stroke:#f59e0b,stroke-width:2px
    style D color:#fff,stroke:#3b82f6,stroke-width:2px

Javadoc Comment Structure #

/**
 * The first sentence is the summary — shown in indexes and IDE tooltips.
 * The following sentences are the detailed description, which can be as long as needed.
 * Use basic HTML for formatting: {@code code}, <b>bold</b>, <ul><li>list</li></ul>.
 *
 * <p>A new paragraph starts with the &lt;p&gt; tag.</p>
 *
 * @param  paramName  description of the parameter (no type — it's already in the signature)
 * @return            what is returned and the conditions under which it's null
 * @throws SomeException  the condition that causes this exception to be thrown
 * @see    AnotherClass#anotherMethod()  cross-reference to other documentation
 * @since  2.0  the first version where this feature is available
 * @deprecated  use {@link #newMethod()} since version 3.0
 */

Javadoc for Classes #

/**
 * Represents a bank account with deposit and withdrawal support.
 *
 * <p>All operations that change the balance are thread-safe because they use
 * {@code synchronized}. However, the order of operations between threads is
 * still not guaranteed without external synchronization.</p>
 *
 * <pre>{@code
 * Account account = new Account("BCA-001", 500_000);
 * account.deposit(100_000);
 * account.withdraw(50_000);
 * System.out.println(account.getBalance()); // 550000.0
 * }</pre>
 *
 * @author  Unis Badri
 * @version 1.2
 * @since   1.0
 * @see     TransactionService
 */
public class Account {
    // ...
}

Javadoc for Methods #

/**
 * Transfers an amount of money from this account to a destination account.
 *
 * <p>The transfer only happens if the source account has enough balance.
 * Both operations (debit and credit) are performed atomically — there is no
 * state where the debit succeeds but the credit fails.</p>
 *
 * @param  destination  the receiving account; must not be {@code null} and must
 *                      not be the same as this account
 * @param  amount       the amount to transfer; must be greater than zero
 * @return              {@code true} if the transfer succeeded,
 *                      {@code false} if the balance is insufficient
 * @throws IllegalArgumentException  if {@code destination} is null, the same
 *                                   as this account, or {@code amount} &lt;= 0
 * @throws AccountLockedException   if either account is currently locked
 * @since  1.1
 */
public boolean transfer(Account destination, double amount) {
    if (destination == null || destination == this) {
        throw new IllegalArgumentException("Invalid destination account");
    }
    if (amount <= 0) {
        throw new IllegalArgumentException("Transfer amount must be positive");
    }
    if (balance < amount) {
        return false;
    }
    this.balance       -= amount;
    destination.balance += amount;
    return true;
}

Javadoc for Fields and Constants #

public class ConnectionConfig {

    /**
     * Maximum number of reconnection attempts before giving up.
     * This value is calibrated against the downstream service SLA — don't
     * raise it without coordinating with the infrastructure team.
     */
    public static final int MAX_RETRY = 5;

    /**
     * Connection timeout in milliseconds.
     *
     * @see #MAX_RETRY
     */
    public static final int TIMEOUT_MS = 3000;

    /**
     * Account number in {@code BANK-XXXX} format where XXXX is
     * four digits. Example: {@code "BCA-0042"}.
     * Must not be {@code null} or empty after object construction.
     */
    private String accountNumber;
}

The Complete Javadoc Tag Set #

Javadoc provides many standard tags. Here are the most frequently used ones along with their usage context:

/**
 * @param  paramName description  — for each method/constructor parameter
 * @return description            — type and conditions of the return value; not for void
 * @throws SomeException reason   — the condition that causes the exception; can be more than one
 * @see    Class#method()         — cross-reference to another class/method
 * @see    <a href="url">text</a> — reference to an external URL
 * @since  version                — the first version it's available
 * @deprecated reason             — marks the API as obsolete + its alternative
 * @author name                   — the author (usually at class level)
 * @version version               — the class version (usually at class level)
 */

Inline tags used inside the description:

/**
 * Examples of inline tags:
 *
 * {@code javaCode}        — renders text as monospace code, HTML-escaped
 * {@link Class#method()}  — hyperlink to another element's documentation
 * {@linkplain Class text} — like @link but with customizable display text
 * {@value CONSTANT}       — inserts the value of a static final constant
 * {@inheritDoc}           — inherits Javadoc from the overridden method
 */

Example of Using the @deprecated Tag #

/**
 * Calculates a discount based on the purchase amount.
 *
 * @param  amount total purchase amount in rupiah
 * @return discount percentage between 0.0 and 1.0
 * @deprecated Use {@link #calculateDiscountV2(double, String)} since version 2.0.
 *             This method doesn't consider product category and will
 *             be removed in version 3.0.
 */
@Deprecated(since = "2.0", forRemoval = true)
public double calculateDiscount(double amount) {
    return amount > 1_000_000 ? 0.15 : 0.05;
}

/**
 * Calculates a discount based on the purchase amount and product category.
 *
 * @param  amount    total purchase amount in rupiah
 * @param  category  product category: "electronics", "fashion", or "food"
 * @return discount percentage between 0.0 and 1.0
 * @since  2.0
 */
public double calculateDiscountV2(double amount, String category) {
    // new implementation
}

Generating HTML Documentation #

After writing Javadoc, you can generate HTML documentation using the javadoc tool that ships with the JDK:

# Generate documentation for all files in the src/ directory
javadoc -d docs -sourcepath src -subpackages com.example

# Generate with encoding and titles
javadoc \
  -d docs \
  -encoding UTF-8 \
  -docencoding UTF-8 \
  -charset UTF-8 \
  -windowtitle "MyApp API Documentation" \
  -doctitle "MyApp v1.0 API" \
  -sourcepath src \
  -subpackages com.example

# Open the result in your browser
open docs/index.html   # macOS
xdg-open docs/index.html  # Linux

With Maven, add this plugin to your pom.xml:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-javadoc-plugin</artifactId>
    <version>3.6.3</version>
    <configuration>
        <encoding>UTF-8</encoding>
        <show>protected</show>
    </configuration>
</plugin>
# Generate via Maven
mvn javadoc:javadoc

# The result is at target/site/apidocs/index.html

Comment Anti-Patterns #

A bad comment is more dangerous than no comment at all — it misleads the reader and creates technical debt.

// ✗ ANTI-PATTERN 1: a comment that repeats the code
// Add tax to the total
total = total + tax;

// Check if stock is empty
if (stock == 0) {

// ✗ ANTI-PATTERN 2: a stale, misleading comment
// Returns the user's first name
public String getUsername() {
    return firstName + " " + lastName; // it actually returns the full name
}

// ✗ ANTI-PATTERN 3: commented-out code without any explanation
// if (debug) logger.info("value: " + value);
// return oldProcess(input);
// additionalValidation(x);

// ✗ ANTI-PATTERN 4: TODO comments that are never resolved
// TODO: fix this later
// TODO: handle edge case
// FIXME: this crashes often

// ✗ ANTI-PATTERN 5: a comment explaining "what" instead of "why"
i = i + 1; // add 1 to i

// ✓ CORRECT: comment design decisions and context invisible in the code
// Use LinkedList instead of ArrayList because the main operation here is
// insertion at the middle — O(1) for LinkedList vs O(n) for ArrayList
List<Task> queue = new LinkedList<>();

// The 200ms delay gives the downstream service time to
// finish its commit before we query. Without it, data could be stale.
// See ticket INFRA-4421 for full context.
Thread.sleep(200);

// Negative price validation isn't done here because it's already validated
// at the API layer before reaching this service. If a negative price gets
// through, that's a bug in the API layer, not here.
this.price = price;
flowchart TD
    A{"Are you about\nto write a comment?"} --> B{"Can the code\nexplain itself with\na better name?"}
    B -- Yes --> C["Rename the variable/method\nDon't write a comment"]
    B -- No --> D{"Does the comment\nexplain WHY\nnot WHAT?"}
    D -- No --> E["Rewrite the comment\nfocus on the reason\nnot the mechanism"]
    D -- Yes --> F{"Is this a\npublic API?"}
    F -- Yes --> G["Write full Javadoc\n@param @return @throws"]
    F -- No --> H["A short // comment\nis enough"]

    style C color:#fff,stroke:#16a34a,stroke-width:2px
    style G color:#fff,stroke:#3b82f6,stroke-width:2px
    style H color:#fff,stroke:#3b82f6,stroke-width:2px

Comments in the IDE #

Modern IDEs like IntelliJ IDEA and VS Code actively use Javadoc — not just to generate HTML, but as a tooltip when you hover over a method or parameter. This means good Javadoc pays off immediately while coding, not only when reading documentation.

/**
 * Searches for products by keyword with pagination.
 *
 * @param  keyword  the search keyword; must not be null, may be empty
 * @param  page     the page number starting from 0 (not 1)
 * @param  size     the number of items per page; max 100
 * @return          the search result page; never null,
 *                  an empty list if there are no results
 */
public Page<Product> search(String keyword, int page, int size) {
    // ...
}

When another developer types search(, the IDE tooltip immediately shows the parameter descriptions — they don’t need to open the source code to understand how to use this method.

As a rule of thumb: every public and protected method in an API used by others must have Javadoc. For internal private code, Javadoc is optional — prioritize self-explanatory code with clear names, and add // comments only for parts that are genuinely confusing.

Summary #

  • Three types of comments// for short single-line explanations, /* */ for multi-line blocks or disabling code, /** */ (Javadoc) for public API documentation that can be generated into HTML.
  • Block comments can’t be nested/* ... /* ... */ ... */ causes a compile error; use several // lines if you need to disable code that already contains a block comment.
  • Javadoc is an API contract@param, @return, and @throws document the behavior a method promises; IDEs display these as tooltips when developers use your method.
  • Comment why, not what — good code already explains what it does; high-value comments explain why a particular decision was made, invisible constraints, or lost context.
  • A stale comment is worse than no comment — a comment that wasn’t updated after the code changed misleads readers; delete or update comments together with code changes.
  • Commented-out code is technical debt — disabled code without explanation confuses people; use version control (git) to keep the history of old code, not comments.
  • @Deprecated + @deprecated — mark obsolete APIs with the @Deprecated(since, forRemoval) annotation and a @deprecated Javadoc explaining the alternative; don’t remove old APIs abruptly.

← Previous: Core Syntax   Next: Exceptions →

About | Author | Content Scope | Editorial Policy | Privacy Policy | Disclaimer | Contact