チームで書いたJavaDocのレビューをしていると、@paramの説明が引数名の言い換えになっているだけだったり、HTMLタグが崩れて生成ドキュメントが読めなくなっているケースをよく見かけます。ルールを一度整理しておくと、レビューの指摘コストが下がります。

はじめに

JavaDocは/** ... */で書いたコメントからjavadocコマンドがHTML形式のAPIドキュメントを自動生成する仕組みだ。 コンパイル可能なコードにさえなっていれば動くため、記述ルールを守らなくてもコンパイルエラーにはならない。 これが「なんとなく書かれたJavaDoc」が量産される最大の理由でもある。

この記事では、以下を実例つきで整理する。

  • クラス・メソッド・フィールドそれぞれの書式ルール
  • @param @return @throws など主要タグの使い方
  • 生成ドキュメントの一覧に表示される「概要文」の作り方
  • HTMLタグの使用制限と{@code}の使い分け
  • Checkstyle・javac -Xdoclintによる自動チェック

JavaDocコメントの基本構文

JavaDocコメントは/**で始まり*/で終わる。通常のブロックコメント/* */とはアスタリスクの数が違うだけだが、 javadocコマンドはこの2文字を目印にコメントを抽出する。対象となる宣言(クラス・メソッド・フィールド等)の直前に置く必要がある。

Java — 基本形
/**
 * 概要文(1文目)。ここは生成された一覧ページのサマリーに使われる。
 *
 * <p>本文。概要文の後は空行を1つ入れて本文に続ける。
 * 補足説明や使用例、注意点などをここに書く。</p>
 *
 * @param input  処理対象の入力値
 * @return 変換後の結果
 * @throws IllegalArgumentException input が null の場合
 */
public String convert(String input) {
    ...
}

構文上のポイントを表にまとめる。

要素ルール
開始タグ/**(アスタリスク2つ)。/*だと通常コメントとして無視される
位置宣言の直前。importやアノテーションを挟むと紐付かない場合がある
概要文と本文空行(*のみの行)で区切る。区切らないと概要文が長くなりすぎる
タグの位置@param 等のブロックタグは本文の最後にまとめて書く
行頭の *整形上の慣習。IDE の自動整形に依存して問題ない

⚠️ アノテーションの位置に注意

@OverrideなどのアノテーションはJavaDocコメントの、宣言の直前に置く。JavaDocコメントとアノテーションの間に余計な行を入れないこと。

クラス・インターフェースのJavaDoc

クラス・インターフェースのJavaDocは「このクラスが何をするものか」を1文目で説明し、責務や利用上の前提を本文に書く。 パッケージ内で完結する実装詳細ではなく、利用者視点で書くのが基本方針だ。

Java — クラスJavaDoc例
/**
 * 全角・半角混在の文字列を正規化するユーティリティ。
 *
 * <p>すべてのメソッドはスレッドセーフであり、内部状態を保持しない。
 * 変換ルールは {@link NormalizeOptions} で指定する。</p>
 *
 * <pre>{@code
 * String result = TextNormalizer.normalize("ABC123", NormalizeOptions.DEFAULT);
 * }</pre>
 *
 * @since 1.2
 * @author acropolis
 */
public final class TextNormalizer {
    private TextNormalizer() {}

    public static String normalize(String input, NormalizeOptions options) {
        ...
    }
}

💡 {@link}で関連クラスを参照する

本文中で別クラス・メソッドに触れるときは平文ではなく{@link ClassName}{@link ClassName#method(Type)}を使う。生成ドキュメント上でクリック可能なリンクになり、リファクタリング時の追跡漏れも減る。

メソッドのJavaDoc — @param・@return・@throws

メソッドのJavaDocは、実装の中身ではなく「何を渡すと何が返るか、どう失敗するか」という契約(コントラクト)を書く。 実装を読まなくても呼び出し方が分かることが目標だ。

Java — メソッドJavaDoc例
/**
 * 指定したユーザーIDに紐づくアクティブな注文一覧を取得する。
 *
 * <p>キャンセル済み・完了済みの注文は結果に含まれない。
 * 該当する注文が1件も無い場合は空リストを返し、{@code null} は返さない。</p>
 *
 * @param userId  検索対象のユーザーID。0以下は無効
 * @param limit   取得件数の上限。0を指定すると上限なしとみなす
 * @return アクティブな注文のリスト(新しい順)。空の場合は空リスト
 * @throws IllegalArgumentException userId が0以下の場合
 * @throws OrderRepositoryException リポジトリへの問い合わせに失敗した場合
 */
public List<Order> findActiveOrders(long userId, int limit) {
    ...
}
タグ書き方のルール
@param引数名で始め、名前の言い換えではなく「何のためにどんな値を渡すか」を書く。単位・範囲・null許容も明記する
@return戻り値の意味を書く。voidメソッドには不要。booleanは「何がtrueなら何を意味するか」を書く
@throws例外クラス名の後に「どの条件で投げるか」を書く。チェック例外は原則すべて記載する

⚠️ 「引数名の言い換え」は @param として無意味

@param userId ユーザーIDのような説明は引数名をそのまま繰り返しているだけで情報量がゼロ。「0以下は無効」「null不可」など、コードを読まないと分からない制約を書くべきタグだ。

フィールド・定数のJavaDoc

publicprotectedのフィールドや定数には、値の意味・単位・変更してよいかどうかを書く。 特にpublic static finalの定数はJavaDoc一覧に表示されるため、単位や既定の使われ方まで書いておくと利用者が迷わない。

Java — フィールドJavaDoc例
/** デフォルトのリクエストタイムアウト(ミリ秒)。 */
public static final int DEFAULT_TIMEOUT_MS = 5000;

/**
 * 再試行の最大回数。
 *
 * <p>0を指定すると再試行を行わない。負数は指定不可。</p>
 */
private int maxRetryCount = 3;

privateフィールドまで書くかはチームの方針で決める

公開APIのフィールドは必須。private フィールドは「読めば分かる」ものまで書くと冗長になりがちなので、単位や不変条件など読んでも分からない情報だけに絞るチームが多い。

よく使うタグ一覧

主要なJavaDocタグを用途別に整理する。

タグ対象用途
@paramメソッド・コンストラクタ引数の意味・制約を説明する
@returnメソッド戻り値の意味を説明する(voidには付けない)
@throws / @exceptionメソッド・コンストラクタ投げる例外と条件を説明する。両者は同義でどちらか一方に統一する
@seeクラス・メソッド全般関連するクラス・メソッド・外部URLへの相互参照を示す
@sinceクラス・メソッド全般導入されたバージョンを記録する。API変更履歴の追跡に使う
@deprecatedクラス・メソッド全般非推奨であることと、代替手段を必ず明記する
@authorクラス作成者を記録する。チーム運用では省略・Git履歴に一任する場合も多い
{@link}本文中クラス・メソッドへのリンクを本文内に埋め込む
{@code}本文中コード断片を<code>相当の見た目で埋め込み、HTMLエスケープも自動化する
{@literal}本文中HTMLとして解釈させたくない文字(< > &)をそのまま表示する
Java — @deprecated の書き方
/**
 * ユーザー情報を取得する。
 *
 * @param id ユーザーID
 * @return ユーザー情報
 * @deprecated バージョン2.0で {@link #findById(long)} に置き換えられた。
 *             次回のメジャーバージョンで削除予定。
 */
@Deprecated(since = "2.0", forRemoval = true)
public User getUser(long id) {
    ...
}

💡 @deprecated と @Deprecated はセットで使う

JavaDocの@deprecatedタグは人間向けの説明、アノテーションの@Deprecatedはコンパイラ向けの警告発生に使われる。片方だけでは不十分で、両方を併記するのが標準的な運用だ。

概要文(最初の1文)のルール

JavaDocの1文目は「概要文(summary sentence)」として扱われ、クラス一覧・メソッド一覧ページにそのまま表示される。 このルールを理解していないと、一覧ページが読みにくいJavaDocになる。

ルール理由
最初の「. 」(ピリオド+空白)までが概要文として抽出される一覧表示に使われるため、途中で意図せず切れないよう1文を短く保つ
「This method...」のような主語の繰り返しを避け、動詞から始める一覧で並べたときに冗長で読みにくくなる
小数点や省略形のピリオド(例: e.g.)に注意するピリオドの直後にスペースがあると概要文がそこで切れてしまう場合がある
概要文だけで内容が推測できるようにするIDEの補完ポップアップにも概要文が使われるため
Before / After
Before: 「This method calculates the total price of the given items and returns it.」
        → 冗長。一覧表示では文末まで見えないことがある

After:  「注文内の商品合計金額を計算する。」
        → 短く、主語を省略した動詞始まりの文

HTMLタグの使用ルール — {@code}と<code>の違い

JavaDocの本文はHTMLとして解釈されるため、<p> <ul> <li>などの基本的なタグが使える。 ただし見出しタグ(<h1>等)や<script>のような構造・実行系タグは使うべきではない。生成ページ自体のレイアウトを壊す可能性があるためだ。

用途推奨理由
コード片の強調{@code text}<code>より短く書け、< > &を自動エスケープする
複数行のコード例<pre>{@code ... }</pre>改行・インデントを保持しつつエスケープも自動化できる
山括弧・アンパサンドをそのまま表示{@literal <, >, &}手動で&lt;等に書き換える手間とミスを防げる
段落分け<p>JavaDocは空行だけでは段落を分けない。明示的な<p>が必要
見出し・スクリプト使用しない生成ドキュメントのレイアウト・セキュリティを壊すおそれがある

⚠️ < > & の直書きは崩れる

ジェネリクスの例として本文中にList<String>とそのまま書くと、HTMLタグとして解釈され表示が崩れる。{@code List<String>}のように{@code}で包むか、&lt; &gt;にエスケープする。

良い例・悪い例の比較

Java — 悪い例
/**
 * ユーザーを取得するメソッド
 * @param id id
 * @return ユーザー
 */
public User getUser(int id) {
    ...
}
Java — 良い例
/**
 * ユーザーIDに対応するユーザー情報を取得する。
 *
 * @param id  検索対象のユーザーID。1以上の正の整数
 * @return 該当するユーザー情報
 * @throws UserNotFoundException id に対応するユーザーが存在しない場合
 */
public User getUser(int id) {
    ...
}
観点悪い例の問題良い例の改善点
概要文「〜するメソッド」は自明で情報量がない「何を渡すと何が返るか」を主語なしの文で説明
@param引数名の言い換えのみ値の範囲・制約を明記
@throws記載が無く、例外時の挙動が不明例外クラスと発生条件を明記

Checkstyle・javac -Xdoclintによる自動チェック

JavaDocのルールはレビュー任せにすると必ず抜け漏れが出る。javac標準の-XdoclintとCheckstyleを組み合わせて機械的に検出するのが実用的だ。

Shell — javac -Xdoclint
# HTML構文エラーや未記載の @param/@return などを警告として検出
javac -Xdoclint:all -d out src/main/java/com/example/**/*.java

# 特定カテゴリだけチェックする場合
javac -Xdoclint:missing,html -d out src/main/java/com/example/**/*.java
XML — checkstyle.xml(JavadocMethod抜粋)
<module name="JavadocMethod">
    <property name="scope" value="public"/>
    <property name="allowMissingParamTags" value="false"/>
    <property name="allowMissingReturnTag" value="false"/>
</module>
<module name="JavadocType">
    <property name="scope" value="public"/>
</module>
<module name="MissingJavadocMethod">
    <property name="scope" value="public"/>
</module>

CIに組み込んで初めて意味を持つ

ローカルで実行するだけではすぐ形骸化する。-Xdoclint:all,-missingのように緩めた設定から始め、Maven/Gradleのビルドやpull request向けCIに組み込み、警告をビルド失敗として扱う運用にすると定着しやすい。

まとめ

この記事のポイントを整理する。

テーマ要点
基本方針 実装の中身ではなく「何を渡すと何が返るか」という利用者向けの契約を書く
@param / @return / @throws 引数名の言い換えではなく、範囲・単位・null許容・例外条件などコードを読まないと分からない情報を書く
概要文 1文目は一覧ページに表示される。短く、動詞から始める
HTML {@code} {@literal}を活用し、山括弧・アンパサンドの直書きを避ける
定着させる仕組み javac -Xdoclint・Checkstyleをレビューではなくビルド/CIに組み込む

次の記事では

JavaDoc生成を手元のIDEに頼らず、Pythonのスクリプトからjavadocコマンドを一括実行し、複数モジュールの生成とログ確認・CI組み込みまでを自動化する方法を解説する。

動作確認環境: JDK 17 / Checkstyle 10.x