1. 程式人生 > >如何寫Java文件註釋(Java Doc Comments)

如何寫Java文件註釋(Java Doc Comments)

如何寫Java文件註釋(Java Doc Comments)

本文翻譯自How to Write Doc Comments for the Javadoc Tool,但是精簡了一些私以為不重要的東西

本文不討論如何使用javadoc工具自動生成文件的方法,而是主要探討應該如何去寫文件註釋

業餘時間整理,難免有遺漏或錯誤,如有發現歡迎指正

轉載請註明

 

文件註釋概覽

“文件註釋”(Java Doc Comments)是專門為了用javadoc工具自動生成文件而寫的註釋,它是一種帶有特殊功能的註釋。

文件註釋與一般註釋的最大區別在於起始符號是/**而不是/*或//。

比如:

複製程式碼
/**
* 這是文件註釋
*/

/*
* 這是一般註釋
*/

// 這是一般註釋
複製程式碼

在一些IDE(比如Eclipse)中,文件註釋會以不同於普通註釋的顏色高亮顯示。

此外,文件註釋只負責描述類(class)、介面(interface)、方法(method)、構造器(constructor)、成員欄位(field)。相應地,文件註釋必須寫在類、介面、方法、構造器、成員欄位前面,而寫在其他位置,比如函式內部,是無效的文件註釋。

文件註釋採用HTML語法規則書寫,支援HTML標記(tag),同時也有一些額外的輔助標記。需要注意的是,這些標記不是給人看的(通常他們的可讀性也不好),他們的作用是為了javadoc工具更好地生成最終文件。所以,雖然有些標記寫起來麻煩且看著不直觀,還是要老老實實按規矩寫滴。

 

文件註釋的基本內容

一個文件註釋由兩部分組成:

/**
* 描述部分(description) 
*
* 標記部分(block tags)
*/

描述部分自然不用多說,所謂的標記符號指的是@param, @return, @see之類的,相信只要看過開源java程式碼的話應該都見過。

 

下面是一個描述一個方法的文件註釋的例子

複製程式碼
/**
 * Returns an Image object that can then be painted on the screen. 
 * The url argument must specify an absolute {
@link URL}. The name * argument is a specifier that is relative to the url argument. * <p> * This method always returns immediately, whether or not the * image exists. When this applet attempts to draw the image on * the screen, the data will be loaded. The graphics primitives * that draw the image will incrementally paint on the screen. * * @param url an absolute URL giving the base location of the image * @param name the location of the image, relative to the url argument * @return the image at the specified URL * @see Image */ public Image getImage(URL url, String name) { try { return getImage(new URL(url, name)); } catch (MalformedURLException e) { return null; } }
複製程式碼

 

需要注意的幾點:

1. 第一行以特殊的文件定界符 /** 開頭

3. 在描述段落和標記段落之間空一行,描述段落和標記段落必須分開,不能揉在一起,描述段落必須在標記段落之前
4. 每一行註釋都應該跟後面描述的類、方法等保持同樣距離的縮排,比如這樣就是錯誤的

複製程式碼
class Image {

/**
* 沒有跟下面的方法保持同樣的縮排
*/
    public Image getImage(URL url, String name) {
        ...
    }
}
複製程式碼

5. 從javadoc 1.4之後,除第一行和最後一行外,可以省略其他行的前導星號(*),但是一般不這麼做

 

描述部分(Description)

描述部分的第一行應該是一句對類、介面、方法等的簡單描述,這句話最後會被javadoc工具提取並放在索引目錄中。

怎麼界定第一句話到哪結束了呢?答案是跟在第一個句號(英文標點)之後的tab、空行或行終結符規定了第一句的結尾。

例如下面這句註釋,第一句的結尾是Prof.:

/**
* This is a simulation of Prof. Knuth's MIX computer.
*/

 

除了普通的文字之外,描述部分可以使用:

1. HTML語法標籤,例如 <b>xxx</b> 

2. javadoc規定的特殊標籤,例如 {@link xxx} 。標籤的語法規則是:{@標籤名 標籤內容}

需要注意的地方:

1. 標籤在有javadoc工具生成文件時會轉化成特殊的內容,比如 {@link URL} 標籤會被轉化成指向URL類的超連結

2. 如果註釋包含多段內容,段與段之間需要用 <p> 分隔,空行是沒用的
3. 最後結尾行 */ 和起始行不同,這裡只有一個星號
4. 為了避免一行過長影響閱讀效果,務必將每行的長度限制在80個字元以內

5. 善用javadoc工具的複製機制避免不必要的註釋:

如果一個方法覆蓋了父類的方法或實現了介面種的方法,那麼javadoc工具會在該註釋裡新增指向原始方法的連結,此外如果新方法沒有註釋,那麼javadoc會把原始方法的註釋複製一份作為其註釋,但是如果新方法有註釋了,就不會複製了。

 

註釋風格:

1. 使用 <code>關鍵字</code> 來強調關鍵字,建議強調的內容有:java關鍵字、包名、類名、方法名、介面名、欄位名、引數名等
2. 控制 {@link xxx} 的數量,太多的連結會使文件的可讀性很差,因為讀者總是跳來跳去。不要出現相同的連結,同樣的連結只保留第一個;不要為java自帶的內容或是常識性的內容提供連結
3. 描述一個方法時,應當只保留方法名字,不要附帶方法的引數。比如有個方法是add(Object obj),那麼用add指代該方法即可,而不是add(Object obj)
4. 英文註釋可以是短語也可以是句子。如果是句子,首字母要大寫,如果是短語,首字母小寫。
5. 英文註釋使用第三人稱,而不是第二人稱。比如:

複製程式碼
/**
* Gets the label(建議) 
*/

/**
* Get the label(不建議)
*/
複製程式碼

 

6. 方法的註釋應該以動詞或動詞片語開頭,因為方法是一個動作。比如:

複製程式碼
/**
* Gets the label of this button(建議)
*/

/**
* This method gets the label(不建議)
*/
複製程式碼

 

7. 當描述類、介面、方法這類的概念時,可以不用指名"類"、"介面"、"方法"這些詞語,比如:

複製程式碼
/**
* A button label (建議)
*/

/**
* This field is a button label (不建議)
*/
複製程式碼

 

8. 英文使用this而不是the指代當前類,比如:

複製程式碼
/**
* Gets the toolkit for this component (建議)
*/

/**
* Gets the toolkit for the component (不建議)
*/
複製程式碼

 

9. API名應該是能夠簡單自我說明的,如果文件註釋只是簡單重複API的名稱還不如沒有文件,所以文件註釋應該至少提供一些額外資訊,否則乾脆不要註釋
10. 英文註釋避免拉丁風格的縮寫。比如使用"also knwon as"而不是"aka", 使用"that is"或"to be specific"而不是"i.e.",使用"for example"而不是"e.g.",使用"in other words"或"namely"而不是"viz."

 

標記部分(Tag)

標記部分跟在描述部分之後,且前面必須有一個空行間隔

常見標記:

1.  @author  作者,沒有特殊格式要求,名字或組織名稱都可以
2.  @version  軟體版本號(注意不是java版本號),沒有特殊格式要求
3.  @param  方法引數,格式為: @param 引數名稱 引數描述 

  • 可以在引數描述中說明引數的型別
  • 可以在引數名稱和引數描述之間新增額外的空格來對齊
  • 破折號或其他標點符號不能出現在引數描述之外的地方

4.  @return  方法返回值,格式為: @return 返回值描述 ,如果方法沒有返回值就不要寫@return
5.  @deprecated 應該告訴使用者這個API被哪個新方法替代了,隨後用 @see 標記或 {@link} 標記指向新API,比如:

/**
* @deprecated As of JDK 1.1, replaced by
* {@link #setBounds(int,int,int,int)}
*/

6.  @throws (或 @exception )包含方法顯式丟擲的檢查異常(Checked Exception),至於非顯示丟擲的其他異常(Unchecked Exception),除非特別有必要,否則就別寫了。一個原則就是,只記錄可控的問題,對於不可控的或不可預測的問題,不要往上面寫。

檢查異常:在try語法塊中觸發,在catch塊中捕獲的異常,這些異常會由編譯器在編譯階段檢查並強制程式設計師處理
非檢查異常:包括執行時異常(RuntimeException)和錯誤(Error)。

 

7. 自定義標記

 

註釋風格:
1. 按照如下順序提供標記

複製程式碼
@author(只出現在類和介面的文件中)
@version(只出現在類和介面的文件中)
@param(只出現在方法或構造器的文件中)
@return(只出現在方法中)
@exception(從java1.2之後也可以使用@thrown替代)
@see
@since
@serial(也可以使用@serialField或@serialData替代)
@deprecated
複製程式碼

此外,如果有多個相同標記,也要注意順序:

多個@author標記,應該按照時間順序排列,即原作者應該排在第一個位置
多個@param標記,應該按照引數定義的順序排列
多個@exception(或是@thrown)應該按照異常的字母順序排列
多個@see標記,應該按照註釋的邏輯順序排列,即從最近的到最遠的,從最具體的到最一般的

2. 必須包含的標記

如果方法有引數,@param標記必須包含,而且每個對應一個引數
如果方法有返回值,@return標記必須包含

 

 

其他註釋

1. 包級別的文件註釋
從java1.2起允許包級別的文件註釋,用以描述包資訊。每個包都可以有自己的包文件註釋,這些註釋被寫在叫package.html的單獨檔案中,並且放至於與原始碼(*.java)相同的路徑下,注意,一定不能單獨放置在其他路徑。
javadoc工具按照以下流程處理package.html:

把主要內容複製到最終生成的package-summary.html檔案中
處理@see, @since, 或{@link}標記
把第一句話複製到javadoc的索引中

 

在包註釋主要介紹一下這個包大致是做什麼用的、背景資訊、在使用方面需要注意的地方等等資訊

2. 匿名、內部類的文件註釋
javadoc不會提取內部類的文件註釋,所以如果想要在最終生成的文件中包含內部類的資訊,方法就是——寫在外部類的文件註釋裡。。

 

一個複雜的文件註釋例子

複製程式碼
/**
 * Graphics is the abstract base class for all graphics contexts
 * which allow an application to draw onto components realized on
 * various devices or onto off-screen images.
 * A Graphics object encapsulates the state information needed
 * for the various rendering operations that Java supports. This
 * state information includes:
 * <ul>
 * <li>The Component to draw on
 * <li>A translation origin for rendering and clipping coordinates
 * <li>The current clip
 * <li>The current color
 * <li>The current font
 * <li>The current logical pixel operation function (XOR or Paint)
 * <li>The current XOR alternation color
 * (see <a href="#setXORMode">setXORMode</a>)
 * </ul>
 * <p>
 * Coordinates are infinitely thin and lie between the pixels of the
 * output device.
 * Operations which draw the outline of a figure operate by traversing
 * along the infinitely thin path with a pixel-sized pen that hangs
 * down and to the right of the anchor point on the path.
 * Operations which fill a figure operate by filling the interior
 * of the infinitely thin path.
 * Operations which render horizontal text render the ascending
 * portion of the characters entirely above the baseline coordinate.
 * <p>
 * Some important points to consider are that drawing a figure that
 * covers a given rectangle will occupy one extra row of pixels on
 * the right and bottom edges compared to filling a figure that is
 * bounded by that same rectangle.
 * Also, drawing a horizontal line along the same y coordinate as
 * the baseline of a line of text will draw the line entirely below
 * the text except for any descenders.
 * Both of these properties are due to the pen hanging down and to
 * the right from the path that it traverses.
 * <p>
 * All coordinates which appear as arguments to the methods of this
 * Graphics object are considered relative to the translation origin
 * of this Graphics object prior to the invocation of the method.
 * All rendering operations modify only pixels which lie within the
 * area bounded by both the current clip of the graphics context
 * and the extents of the Component used to create the Graphics object.
 * 
 * @author Sami Shaio
 * @author Arthur van Hoff
 * @version %I%, %G%
 * @since 1.0
 */
public abstract class Graphics {

    /** 
     * Draws as much of the specified image as is currently available
     * with its northwest corner at the specified coordinate (x, y).
     * This method will return immediately in all cases, even if the
     * entire image has not yet been scaled, dithered and converted
     * for the current output device.
     * <p>
     * If the current output representation is not yet complete then
     * the method will return false and the indicated 
     * {@link ImageObserver} object will be notified as the
     * conversion process progresses.
     *
     * @param img the image to be drawn
     * @param x the x-coordinate of the northwest corner
     * of the destination rectangle in pixels
     * @param y the y-coordinate of the northwest corner
     * of the destination rectangle in pixels
     * @param observer the image observer to be notified as more
     * of the image is converted. May be 
     * <code>null</code>
     * @return <code>true</code> if the image is completely 
     * loaded and was painted successfully; 
     * <code>false</code> otherwise.
     * @see Image
     * @see ImageObserver
     * @since 1.0
     */
    public abstract boolean drawImage(Image img, int x, int y, 
                                      ImageObserver observer);


    /**
     * Dispose of the system resources used by this graphics context.
     * The Graphics context cannot be used after being disposed of.
     * While the finalization process of the garbage collector will
     * also dispose of the same system resources, due to the number
     * of Graphics objects that can be created in short time frames
     * it is preferable to manually free the associated resources
     * using this method rather than to rely on a finalization
     * process which may not happen for a long period of time.
     * <p>
     * Graphics objects which are provided as arguments to the paint
     * and update methods of Components are automatically disposed
     * by the system when those methods return. Programmers should,
     * for efficiency, call the dispose method when finished using
     * a Graphics object only if it was created directly from a
     * Component or another Graphics object.
     *
     * @see #create(int, int, int, int)
     * @see #finalize()
     * @see Component#getGraphics()
     * @see Component#paint(Graphics)
     * @see Component#update(Graphics)
     * @since 1.0
     */
    public abstract void dispose();

    /**
     * Disposes of this graphics context once it is no longer 
     * referenced.
     *
     * @see #dispose()
     * @since 1.0
     */
    public void finalize() {
        dispose();
    }
}
複製程式碼