??如果API要可用顾翼,就必須對其進行文檔化投放。傳統(tǒng)上,API文檔是手工生成的适贸,保持與代碼的同步是一件苦差事灸芳。Java編程環(huán)境使用Javadoc實用程序簡化了這一任務。Javadoc使用特殊格式的文檔注釋(通常稱為doc注釋)從源代碼自動生成API文檔拜姿。
??雖然doc注釋約定不是正式語言的一部分烙样,但它們實際上構(gòu)成了每個Java程序員都應該知道的API。這些約定在如何編寫Doc注釋web頁面[Javadocguide]中進行了描述蕊肥。雖然自Java 4發(fā)布以來這個頁面沒有更新谒获,但它仍然是一個非常寶貴的資源。在Java 9中添加了一個重要的doc標簽壁却,{@index};Java 8中的一個究反,{@implSpec};Java 5中有兩個,{@literal}和{@code}儒洛。上述web頁面中缺少這些標記精耐,但將在本項目中討論。
??要正確地記錄API琅锻,必須在每個導出的類卦停、接口、構(gòu)造函數(shù)恼蓬、方法和字段聲明之前加上doc注釋惊完。如果一個類是可序列化的,還應該記錄它的序列化形式(item87 )处硬。在缺少doc注釋的情況下小槐,Javadoc所能做的最好的事情就是將聲明復制為受影響API元素的唯一文檔。使用缺少文檔注釋的API是令人沮喪和容易出錯的荷辕。公共類不應該使用默認構(gòu)造函數(shù)凿跳,因為無法為它們提供doc注釋。要編寫可維護的代碼疮方,還應該為大多數(shù)未導出的類控嗜、接口、構(gòu)造函數(shù)骡显、方法和字段編寫doc注釋疆栏,盡管這些注釋不需要像導出API元素那樣完整曾掂。
??方法的doc注釋應該簡潔地描述方法與其客戶機之間的契約。除為繼承而設計的類中的方法(item19 )外壁顶,契約應該說明方法做了什么珠洗,而不是它如何做它的工作。doc注釋應該枚舉方法的所有前置條件(這些條件必須為真若专,以便客戶機調(diào)用它們)和后置條件(這些條件是在調(diào)用成功完成后才為真)险污。通常,先決條件是通過@throw標簽的未檢查異常隱式描述的富岳;每個未檢查異常對應于一個先決條件違反蛔糯。此外,可以在前置條件及其@param標記中指定受影響的參數(shù)窖式。
??除了前置條件和后置條件外蚁飒,方法還應該記錄任何副作用。副作用是系統(tǒng)狀態(tài)的一個可觀察到的變化萝喘,它不是實現(xiàn)后置條件所明顯需要的淮逻。例如,如果一個方法啟動了一個后臺線程阁簸,文檔應該注意它爬早。
??要完整地描述方法的契約,doc注釋應該為每個參數(shù)都有一個@param標記启妹,一個@return標記(除非方法有一個void返回類型)筛严,以及一個@throw標記(對于方法拋出的每個異常,無論是否是可檢查的)( item74 )饶米。如果@return標記中的文本與方法的描述相同桨啃,則可以忽略它,這取決于您所遵循的編碼標準檬输。
??按照慣例照瘾,@param標記或@return標記后面的文本應該是一個名詞短語,描述參數(shù)或返回值所表示的值丧慈。算術(shù)表達式很少用來代替名詞短語;有關(guān)示例析命,請參見BigInteger。@throw標記后面的文本應該包含單詞“if”逃默,后跟描述引發(fā)異常的條件的子句鹃愤。按照慣例,@param笑旺、@return或@throw標記后面的短語或子句不以句號結(jié)束昼浦。:以下的doc注釋說明了所有這些約定:
??請注意在這個doc注釋中使用HTML標記(<p> 和<i>). 。Javadoc實用程序?qū)oc注釋轉(zhuǎn)換為HTML, doc注釋中的任意HTML元素最終會出現(xiàn)在生成的HTML文檔中筒主。有時候关噪,程序員甚至會在他們的doc注釋中嵌入HTML表,盡管這種情況很少見乌妙。
??還要注意在@throw子句中的代碼片段周圍使用Javadoc {@code}標記使兔。這個標記有兩個目的:它使代碼片段以代碼字體呈現(xiàn),并且它抑制了代碼片段中HTML標記和嵌套Javadoc標記的處理藤韵。后一個屬性允許我們在代碼片段中使用小于號(<)虐沥,即使它是一個HTML元字符。要在doc注釋中包含多行代碼示例泽艘,使用Javadoc {@code}標記封裝在HTML<pre>標記中欲险。換句話說,在代碼示例之前加上字符<pre>{@code and follow it with }</pre>.這保護線在代碼中中斷匹涮,并消除了轉(zhuǎn)義HTML元字符的需要天试,但不需要轉(zhuǎn)義at符號(@),如果代碼示例使用注釋然低,則必須轉(zhuǎn)義@喜每。
??最后,請注意doc注釋中使用的單詞“this list”雳攘。按照慣例带兜,“this”指的是在doc注釋中為實例方法使用方法時調(diào)用方法的對象。
??正如第15項中提到的吨灭,當您為繼承設計一個類時刚照,您必須記錄它的自用模式,以便程序員知道覆蓋它的方法的語義喧兄。這些自用模式應該使用在Java 8中添加的@implSpec標記來記錄涩咖。回想一下繁莹,普通的doc注釋描述了方法與其客戶機之間的契約;相反檩互,@implSpec注釋描述了方法與其子類之間的契約,允許子類依賴于實現(xiàn)行為(如果它們繼承了方法或通過super調(diào)用方法)咨演。下面是它在實踐中的樣子:
??Java 9開始闸昨,Javadoc實用程序仍然忽略@implSpec標記,除非您通過命令行開關(guān)-標記“implSpec:a:Implementation Requirements:”薄风。希望在后續(xù)的版本中可以糾正這個錯誤饵较。
??不要忘記,您必須采取特殊的操作來生成包含HTML元字符的文檔遭赂,比如小于號(<)循诉、大于號(>)和與號(&)。將這些字符放到文檔中最好的方法是用{@literal}標記包圍它們撇他,這將抑制HTML標記和嵌套Javadoc標記的處理茄猫。它類似于{@code}標記狈蚤,只是它不以代碼字體呈現(xiàn)文本。例如划纽,這個Javadoc片段:
??生成文檔:“如果|r| < 1脆侮,則幾何級數(shù)收斂∮铝樱”使用相同的結(jié)果文檔靖避,{@literal}標記可以放在小于號周圍,而不是整個不等式周圍比默,但是doc注釋在源代碼中可讀性較差幻捏。:這說明了doc注釋在源代碼和生成的文檔中都應該是可讀的。如果不能同時實現(xiàn)這兩個目標命咐,生成的文檔的可讀性將超過源代碼的可讀性篡九。
??每個doc注釋的第一個“句子”(定義如下)成為注釋所屬元素的摘要描述。例如侈百,255頁doc注釋中的摘要描述是“返回列表中指定位置的元素”瓮下。摘要描述必須獨立地描述它總結(jié)的元素的功能。為了避免混淆,類或接口中的任何兩個成員或構(gòu)造函數(shù)都不應具有相同的摘要描述钝域。特別注意重載讽坏,對于重載,通常使用相同的第一句話是很自然的(但在doc注釋中是不可接受的)例证。
??如果預期的摘要描述包含句點路呜,請小心,因為句點可能會提前終止描述织咧。例如胀葱,以短語開頭的doc注釋"“A college degree, such as B.S., M.S. or Ph.D.”將在總結(jié)描述的結(jié)果““A college degree, such as B.S., M.S.” ”問題是摘要描述在第一個句點結(jié)束,然后是空格笙蒙、制表符或行結(jié)束符(或第一個塊標記)[Javadoc-ref]抵屿。這里是縮寫“M.S.”中的第二個句號后面跟著一個空格。最好的解決方案是用{@literal}標記來包圍違規(guī)的句點和任何相關(guān)的文本捅位,這樣源代碼中的句點后面就不會有空格了:
??說摘要描述是doc注釋中的第一句話有點誤導人轧葛。按照慣例,它很少應該是一個完整的句子艇搀。對于方法和構(gòu)造函數(shù)尿扯,摘要描述應該是一個動詞短語(包括任何對象),描述方法執(zhí)行的操作焰雕。例如:
??如這些例子所示衷笋,使用第三人稱陳述句時態(tài)(“return the number”)而不是第二人稱祈使句(“return the number”)。
??對于類矩屁、接口和字段辟宗,摘要描述應該是一個名詞短語爵赵,描述由類或接口的實例或字段本身表示的事物。例如:
??在Java 9中慢蜓,客戶端索引被添加到Javadoc生成的HTML中亚再。這個索引以頁面右上角的搜索框的形式出現(xiàn)郭膛,它簡化了導航大型API文檔集的任務晨抡。當您在框中鍵入時,您將得到一個匹配頁面的下拉菜單则剃。API元素(如類耘柱、方法和字段)是自動索引的。有時棍现,您可能希望索引對您的API很重要的其他術(shù)語调煎。為此添加了{@index}標記。對doc注釋中出現(xiàn)的術(shù)語進行索引己肮,就像將其包裝在這個標簽中一樣簡單士袄,如下面的片段所示:
- This method complies with the {@index IEEE 754} standard.
??泛型、枚舉和注釋在doc注釋中需要特別注意谎僻。當記錄泛型類型或方法時娄柳,請確保記錄所有類型參數(shù):
??在記錄枚舉類型時,一定要記錄常量艘绍、類型和任何公共方法赤拒。注意,如果文檔很短诱鞠,你可以把整個文檔注釋放在一行:
??在記錄注釋類型時挎挖,一定要記錄任何成員和類型本身。用名詞短語記錄成員航夺,就好像它們是字段一樣蕉朵。對于類型的摘要描述,請使用動詞短語阳掐,它表示當程序元素具有此類注釋時的含義:
??包級別的doc注釋應該放在名為packageinfo.java的文件中始衅。除了這些注釋之外,package-info.java必須包含一個包聲明锚烦,并且可能包含關(guān)于這個聲明的注釋觅闽。類似地,如果您選擇使用模塊系統(tǒng)( item15)涮俄,模塊級別的注釋應該放在模塊-info.java文件中蛉拙。
??在文檔中經(jīng)常忽略的api的兩個方面是線程安全性和可序列化性。無論類或靜態(tài)方法是否線程安全彻亲,都應該記錄它的線程安全級別孕锄,如項目82所述吮廉。如果一個類是可序列化的,您應該記錄它的序列化形式畸肆,如第87項中所述宦芦。
??Javadoc具有“繼承”方法注釋的能力。如果API元素沒有doc注釋轴脐,Javadoc將搜索最特定的適用doc注釋调卑,優(yōu)先選擇接口而不是超類。搜索算法的詳細信息可以在Javadoc參考指南[Javadoc-ref]中找到大咱。您還可以使用{@inheritDoc}標記從超類型繼承部分doc注釋恬涧。:這意味著類可以重用它們實現(xiàn)的接口中的doc注釋,而不是復制這些注釋碴巾。這個工具有潛力減少維護多個幾乎相同的doc注釋集的負擔溯捆,但是它使用起來很棘手,并且有一些限制厦瓢。這些細節(jié)超出了這本書的范圍提揍。
??關(guān)于文檔注釋,應該添加一個警告煮仇。雖然有必要為所有導出的API元素提供文檔注釋劳跃,但這并不總是足夠的。對于由多個相互關(guān)聯(lián)的類組成的復雜api欺抗,通常需要用描述API總體架構(gòu)的外部文檔來補充文檔注釋售碳。如果存在這樣的文檔,相關(guān)的類或包文檔注釋應該包含到它的鏈接绞呈。
??Javadoc會自動檢查是否符合本項目中的許多建議贸人。在Java 7中,需要命令行開關(guān)-Xdoclint來獲得這種行為佃声。在Java 8和Java 9中艺智,默認情況下啟用了check。諸如checkstyle之類的IDE插件在檢查是否符合這些建議方面走得更遠[Burn01]圾亏。還可以通過HTML有效性檢查器運行Javadoc生成的HTML文件來降低doc注釋中出現(xiàn)錯誤的可能性十拣。這將檢測HTML標記的許多不正確用法。有幾個這樣的檢查器可供下載志鹃,您可以使用W3C標記驗證服務[W3C-validator]在web上驗證HTML夭问。在驗證生成的HTML時,請記住曹铃,從Java 9開始缰趋,Javadoc就能夠生成HTML5和HTML 4.01,盡管默認情況下它仍然生成HTML 4.01。如果希望Javadoc生成HTML5秘血,請使用-html5命令行開關(guān)味抖。
??本項目中描述的約定涵蓋了基本內(nèi)容。盡管撰寫本文時已經(jīng)有15年的歷史灰粮,但編寫doc注釋的最終指南仍然是如何編寫doc注釋[Javadoc-guide]仔涩。
??如果您遵循本項目中的指導原則,生成的文檔應該提供對API的清晰描述粘舟。然而熔脂,唯一確定的方法是閱讀Javadoc實用程序生成的web頁面。對于其他人將使用的每個API蓖乘,都值得這樣做锤悄。正如測試程序幾乎不可避免地會導致對代碼的一些更改一樣韧骗,閱讀文檔通常也會導致對doc注釋的一些較小更改嘉抒。
??總之,文檔注釋是記錄API的最佳袍暴、最有效的方法些侍。應該認為所有導出的API元素都必須使用它們。采用符合標準約定的一致樣式政模。請記住岗宣,在文檔注釋中允許任意HTML,并且必須轉(zhuǎn)義HTML元字符淋样。
本文寫于2019.7.18耗式,歷時1天