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:2pxJavadoc 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 <p> 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} <= 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:2pxComments 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: everypublicandprotectedmethod 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@throwsdocument 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@deprecatedJavadoc explaining the alternative; don’t remove old APIs abruptly.