国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁(yè) > 學(xué)院 > 開發(fā)設(shè)計(jì) > 正文

采用 Javadoc 形式的集成文檔有利有弊

2019-11-18 15:12:07
字體:
來(lái)源:轉(zhuǎn)載
供稿:網(wǎng)友

java 語(yǔ)言按照 Javadoc 注釋約定采用了一種集成的方法來(lái)進(jìn)行 API 文檔編制。Javadoc 工具可以幫助生成好的 API 文檔,然而大多數(shù) Java API 文檔卻很糟糕。因?yàn)樗窃创a的一部分,所以 API 的文檔編制職責(zé)最終還是落到了工程師身上。在本文中,Brian 對(duì) Java 文檔編制實(shí)踐的當(dāng)前狀態(tài)進(jìn)行了嚴(yán)厲的批評(píng),同時(shí)提供了一些關(guān)于如何編寫更有用的 Javadoc 的準(zhǔn)則。
對(duì)于大多數(shù) Java 類庫(kù)來(lái)說(shuō),Javadoc 是唯一的文檔。而且,除了商業(yè)軟件組件之外,許多 Java 類不會(huì)用到 Javadoc。雖然 Javadoc 作為 API 參考工具很出色,但對(duì)于了解類庫(kù)是如何組織的和應(yīng)該如何使用它來(lái)說(shuō),它卻是一種十分差勁的方法。并且即便用了 Javadoc,它通常只包含有關(guān)方法完成了什么的最基本信息,而忽略了諸如錯(cuò)誤處理、參數(shù)及返回值的作用域和范圍、線程安全、鎖定行為、前置條件、后置條件、不變條件或副作用之類的重要特性。

向 Javadoc 學(xué)習(xí)
對(duì)于包括大多數(shù)開放源碼包和大多數(shù)內(nèi)部開發(fā)的組件在內(nèi)的許多 Java 工具而言,實(shí)際情況是:包括 Javadoc 在內(nèi),幾乎所有類庫(kù)或組件都不具有有效的文檔。這就意味著開發(fā)人員要從 Javadoc 學(xué)習(xí)使用工具,而且我們應(yīng)該考慮根據(jù)這一現(xiàn)實(shí)組織我們的 Javadoc。我經(jīng)常開玩笑說(shuō):現(xiàn)在,Java 程序員需要具備的最重要的技能之一是熟練地使用 Google 和 Javadoc 來(lái)對(duì)那些文檔編制得十分糟糕的 API 進(jìn)行“逆向工程”。這可能是真的,但卻并不十分好笑。

大多數(shù) Java 包都有某種“根”對(duì)象,它是在得到該工具內(nèi)的任何其它對(duì)象之前,必須創(chuàng)建的第一個(gè)對(duì)象。在 JNDI 中,該根對(duì)象是 Context,而在 JMS 和 JDBC 中,它是 Connection。假如有人告訴您 JDBC 中的基礎(chǔ)對(duì)象是 Connection,以及如何獲得這一對(duì)象,那么接著您很可能會(huì)從 Javadoc 中通過(guò)仔細(xì)察看 Javadoc 中可用的方法列表找到如何創(chuàng)建并執(zhí)行 Statement,以及如何迭代生成的 ResultSet。但您如何知道獲得 Connection 是您的第一步呢?Javadoc 在包內(nèi)按照字母順序組織類,在類中按照字母順序組織方法。遺憾的是,Javadoc 中沒(méi)有神奇的“從這里開始(Start Here)”記號(hào)把讀者帶到瀏覽 API 的邏輯開始位置。

包描述
最接近“從這里開始”記號(hào)的是包描述,但它卻很少得到有效的使用。假如將文件 package.Html 與源代碼一起放在一個(gè)包中,那么標(biāo)準(zhǔn)的 doclet 會(huì)將已生成的 package-summary.html 文件中的內(nèi)容連同類列表一起放在該包內(nèi)。遺憾的是,生成我們都很熟悉的 HTML 文檔的標(biāo)準(zhǔn) doclet 卻無(wú)法使包描述易于找到。假如您單擊左上窗格中的某個(gè)包,那么這會(huì)在左下窗格中產(chǎn)生方法列表,但并不會(huì)在主窗格中產(chǎn)生包的摘要 ? 必須單擊左下窗格中的包名稱來(lái)查看摘要。但不要緊,究竟大多數(shù)包并沒(méi)有包描述。

包文檔是一個(gè)放置“從這里開始”文檔的極好的地方,這一文檔用來(lái)概述包做什么、主要摘要是什么以及從何處開始瀏覽包的 Javadoc。

類文檔
除包文檔之外,特定于類的文檔對(duì)于幫助用戶徹底了解新工具也能起到重要的作用。類文檔當(dāng)然應(yīng)該包括此特定類做什么的描述,但還應(yīng)該描述該類與包中的其它類如何關(guān)聯(lián),非凡是要標(biāo)識(shí)任何與該類相關(guān)的工廠類。例如,JDBC 中的 Statement 類文檔應(yīng)該說(shuō)明:Statement 是通過(guò) Connection 類的 createStatement() 方法獲得的。這樣,假如一個(gè)新用戶偶然進(jìn)入 Statement 頁(yè)面,那么他會(huì)發(fā)現(xiàn)首先他需要獲得 Connection。對(duì)每個(gè)類都應(yīng)用這一約定的包會(huì)迅速為用戶指出根對(duì)象,用戶因而能夠得心應(yīng)手。

因?yàn)?Javadoc 是圍繞對(duì)特定類進(jìn)行文檔編制而設(shè)計(jì)的,因此在 Javadoc 中通常沒(méi)有明顯的位置來(lái)放置演示幾個(gè)相關(guān)類一起使用的示例代碼。但由于一味地側(cè)重于特定類或方法的文檔編制,我們失去了討論如何組合包中內(nèi)容的機(jī)會(huì)。假如對(duì)于根對(duì)象,在包文檔或類文檔中有一個(gè)演示一些基本用法的簡(jiǎn)單代碼示例,則對(duì)于許多用戶來(lái)說(shuō),將是非常有用的。例如,Connection 類文檔可以有一個(gè)簡(jiǎn)單示例,該示例獲取連接、創(chuàng)建預(yù)編譯語(yǔ)句、執(zhí)行該語(yǔ)句并迭代結(jié)果集。從技術(shù)上說(shuō),這可能不屬于 Connection 頁(yè)面,因?yàn)樗€描述了包中的其它類。然而,尤其是當(dāng)結(jié)合了上面那種引用當(dāng)前類所依靠的類的技術(shù)時(shí),用戶才能非常迅速地找到獲取簡(jiǎn)單的實(shí)用示例的途徑,不管類的組織方式如何。

糟糕的文檔 == 糟糕的代碼
對(duì)于大多數(shù) Java 類庫(kù)來(lái)說(shuō),除了那些作為打包組件出售的商業(yè)產(chǎn)品之外,要么沒(méi)有 Javadoc,要么非常糟糕。由于存在的事實(shí)是對(duì)于大多數(shù)包來(lái)說(shuō),Javadoc 是我們擁有的唯一文檔,這基本上意味著使我們自己陷入了這樣的困境:除了作者之外,其他人沒(méi)法使用我們的大部分代碼 ? 假如不付出重大的“考古”一樣的努力,至少會(huì)這樣。

由于文檔現(xiàn)在是代碼的一部分,因此我認(rèn)為是軟件工程社區(qū)形成一個(gè)共識(shí)的時(shí)候了,這就是,即使代碼很出色,假如文檔很糟糕,也應(yīng)該被認(rèn)為是差勁的代碼,因?yàn)椴荒苡行У刂赜?。單元測(cè)試不久前還聲譽(yù)不佳,只是到了最近它才受到了許多工程師的青睞,就和它一樣,為了改善我們生產(chǎn)的軟件的可靠性和可重用性,API 文檔也必須成為開發(fā)過(guò)程的一個(gè)集成部分。

編寫 Javadoc 就是某種形式的代碼檢查
編寫合理的 Javadoc 也會(huì)產(chǎn)生副作用,它迫使我們進(jìn)行某種形式的代碼檢查,來(lái)研究類的體系結(jié)構(gòu)和它們之間的關(guān)系。假如單個(gè)包、類或方法很難編制文檔,那么或許可以嘗試同時(shí)對(duì)多個(gè)包、類或方法進(jìn)行文檔編制,這應(yīng)該是個(gè)提示,即可能它需要重新設(shè)計(jì)。

文檔的自我檢查方面使得某些方面更加重要,即在開發(fā)過(guò)程中盡早編寫 Javadoc,然后隨著代碼的不斷開發(fā),定期對(duì)其進(jìn)行檢查,而不是僅僅等待代碼完成再編寫文檔(假如有剩余時(shí)間的話)。后一種策略十分常見,它將編寫文檔拖到項(xiàng)目最后,而那時(shí)時(shí)間安排十分緊張,開發(fā)人員的壓力也很大。結(jié)果再常見不過(guò)了,就是圖 1 所示的那種一文不值的文檔,它只提供了“文檔假象”。用戶真正需要的是了解該類的工作原理,而該文檔卻沒(méi)有提供任何這樣的信息。

清單 1. 典型的一文不值的 Javadoc
/**
* RePResents a command history
*/
public class CommandHistory {

/**
* Get the command history for a given user
*/
public static CommandHistory getCommandHistory(String user) {
. . .
}
}

那么好的文檔包括哪些內(nèi)容呢?
上面描述的組織技術(shù)(在類描述中引用相關(guān)類或工廠類,也包括了包概述和代碼樣本)是形成優(yōu)秀文檔的好開端。它有助于新用戶使用 Javadoc 了解新工具。

但體系結(jié)構(gòu)的概述只完成了任務(wù)的一半。另一半則是具體地解釋方法做什么和不做什么、在什么條件下運(yùn)行以及它們?nèi)绾翁幚礤e(cuò)誤條件。大多數(shù) Javadoc 都沒(méi)有完全提供所需的信息,即便是那些充分描述了方法在期望情況下的行為的 Javadoc 也是如此,這些缺少的信息包括:

方法如何處理錯(cuò)誤條件或不合要求的輸入
如何將錯(cuò)誤條件傳回給調(diào)用者
可能會(huì)拋出哪個(gè)特定異常的子類
哪些值對(duì)于輸入是有效的
類不變條件、方法前置條件或方法后置條件
副作用
在方法之間是否有重要聯(lián)接
類如何處理多個(gè)線程同時(shí)訪問(wèn)一個(gè)實(shí)例的情況。
Javadoc 約定提供了 @param 標(biāo)記,它讓我們除了能夠?qū)?shù)的名稱和類型編制文檔之外,還可以對(duì)其意義編制文檔。然而,并不是所有的方法都能很好地接受參數(shù)的任何值。例如,雖然可以合法地向任何獲取對(duì)象參數(shù)的方法傳遞空值(null)而不違反類型檢查規(guī)則,但并不是所有的方法都能在傳入空值時(shí)正常工作。Javadoc 應(yīng)該顯式地描述有效的參數(shù)范圍,假如它希望某個(gè)參數(shù)非 null,那么它應(yīng)該這樣描述,而假如它期望參數(shù)值在某個(gè)范圍內(nèi),例如某種長(zhǎng)度的字符串或大于 0 的整數(shù),那么它也應(yīng)該那樣描述。并非所有方法都仔細(xì)檢查其參數(shù)的有效性;不進(jìn)行有效性檢查也沒(méi)有編制關(guān)于可接受的輸入范圍的文檔,這二者的結(jié)合為災(zāi)難埋下了隱患。

返回代碼
Javadoc 使得描述返回值的意義變得很輕易,但正如方法參數(shù)一樣,@return 標(biāo)記應(yīng)該包括對(duì)可能返回的值范圍的具體描述。對(duì)于對(duì)象取值的返回類型而言,它會(huì)返回空值嗎?對(duì)于整數(shù)取值的返回類型而言,結(jié)果會(huì)限制在一個(gè)已知值或非負(fù)值的集合上嗎?任何返回代碼都有非凡意義嗎,例如從 java.io.InputStream.read() 返回 -1 表示文件結(jié)束符?返回代碼會(huì)被用來(lái)表示例如假如無(wú)法找到表項(xiàng)則返回空值那樣的錯(cuò)誤條件嗎?

異常
標(biāo)準(zhǔn) doclet 復(fù)制方法的 throws 子句,但 Javadoc @throws 標(biāo)記應(yīng)該更為具體。例如,NoSUChFileException 是 IOException 的子類,但 java.io 中的大多數(shù)方法卻只被聲明為拋出 IOException。然而,方法可能獨(dú)立于其它 IOException 而拋出 NoSuchFileException,這是調(diào)用者要了解的很有用的事實(shí) ? 它應(yīng)該被包括在 Javadoc 中。還應(yīng)該指出拋出各種異常類的實(shí)際錯(cuò)誤條件,以便調(diào)用者知道在給定異常被拋出時(shí)該采取什么糾正措施。應(yīng)該用 @throws 標(biāo)記對(duì)方法可能拋出的每個(gè)經(jīng)檢查的或未經(jīng)檢查的異常編制文檔,并對(duì)引發(fā)拋出異常的條件編制文檔。

前置條件、后置條件和不變條件
當(dāng)然,您應(yīng)該對(duì)方法對(duì)對(duì)象狀態(tài)的影響編制文檔。但您可能需要編制得更具體一些,描述方法的前置條件、后置條件和類不變條件。前置條件是在調(diào)用方法前對(duì)對(duì)象狀態(tài)的約束;例如,調(diào)用 Iterator.next() 的前置條件是 hasMore() 為真。后置條件是方法調(diào)用完成后對(duì)對(duì)象狀態(tài)的約束,例如在調(diào)用 add() 之后 List 不能為空。不變條件是對(duì)對(duì)象狀態(tài)的一種約束,它保證該狀態(tài)始終為真,例如 Collection.size() == Collection.toArray().length()。

諸如 jContract 之類的按契約設(shè)計(jì)(Design-by-contract)工具答應(yīng)您使用非凡注釋指定前置條件、后置條件和類不變條件,這類工具然后生成額外代碼來(lái)強(qiáng)制這些約束。無(wú)論您是否使用工具來(lái)強(qiáng)制這些期望條件,對(duì)這些約束編制文檔可以讓用戶知道要安全地使用類,他們可以做些什么。

副作用
有時(shí)候,方法除了改變對(duì)象狀態(tài)之外還會(huì)有其它副作用,例如改變相關(guān)對(duì)象、JVM 或底層計(jì)算平臺(tái)的狀態(tài)。例如,所有執(zhí)行 I/O 的方法都有副作用。有些副作用是無(wú)害的,例如保留類處理的請(qǐng)求的記數(shù)。另外一些副作用則會(huì)對(duì)程序性能和正確性產(chǎn)生重大影響,例如修改傳遞給方法的對(duì)象的狀態(tài),或存儲(chǔ)對(duì)該對(duì)象的引用的副本。諸如修改相關(guān)對(duì)象的狀態(tài)或存儲(chǔ)對(duì)作為方法參數(shù)傳遞的對(duì)象的引用之類的副作用應(yīng)該編制文檔。

方法聯(lián)接
方法聯(lián)接意味著類中的兩個(gè)方法相互依靠,并且都對(duì)對(duì)方的行為做了假定。發(fā)生方法聯(lián)接的一種常見情形是:方法在內(nèi)部使用同一個(gè)類的 toString 方法,并假定 toString 將以非凡的方法格式化對(duì)象狀態(tài)。假如該類已經(jīng)子類化并且 toString 方法被重寫了,那么這種情形可能引起問(wèn)題;另一個(gè)方法會(huì)忽然不能正常工作,除非它也被重寫。假如您的方法依靠于其它方法的實(shí)現(xiàn)行為,那么需要對(duì)那些依靠性編制文檔。而且,假如類已子類化,那么可以以一致的方式重寫兩種方法以便使子類仍能正常工作。

線程安全
應(yīng)該編制文檔的最重要的行為之一是線程安全,而對(duì)它幾乎從未編制文檔。這個(gè)類是線程安全的嗎?假如不是,那么是否可以通過(guò)用同步封裝調(diào)用來(lái)使其線程安全嗎?這些同步必須同特定管程相關(guān)聯(lián),還是任何一直使用的管程都可以使用呢?方法獲得了對(duì)于類外部是可見的對(duì)象的鎖嗎?

線程安全實(shí)際上不是二進(jìn)制屬性;線程安全有幾種可標(biāo)識(shí)的等級(jí)。對(duì)線程安全編制文檔,或者甚至確定線程安全的等級(jí)并非總是很輕易。但未能進(jìn)行這一工作將導(dǎo)致嚴(yán)重的問(wèn)題;在并發(fā)應(yīng)用程序中使用非線程安全類可能引起零星的故障,這些故障經(jīng)常直到部署時(shí)才出現(xiàn)(那時(shí)暴露應(yīng)用程序以便裝入)。而且將額外鎖定封裝在已經(jīng)是線程安全的類四周會(huì)影響性能,甚至引起死鎖。

Josh Bloch 在他的 Effective Java Programming Language Guide(參閱參考資料)一書中對(duì)類的線程安全等級(jí)編制文檔提供了有用的分類法。可以按照線程安全遞減順序?qū)㈩悮w到下列某一組:不可變、線程安全、有條件的線程安全、線程兼容和線程對(duì)立。

這種分類是一個(gè)極佳的框架,用于在并發(fā)訪問(wèn)情況下傳遞關(guān)于類行為的重要信息。不管您是否使用這一分類法都沒(méi)關(guān)系,但您應(yīng)該標(biāo)識(shí)您的類意圖顯示的線程安全等級(jí)。我還建議:假如方法獲得對(duì)一個(gè)對(duì)象的鎖定,而該對(duì)象對(duì)于類自身的代碼外部是可見的,那么您也應(yīng)該就此編制文檔,即使這只是一個(gè)“實(shí)現(xiàn)細(xì)節(jié)”,以便協(xié)助做出全局鎖定順序(global-lock-order)決策并防止死鎖。

結(jié)束語(yǔ)
對(duì)類的行為編制文檔遠(yuǎn)遠(yuǎn)不只是對(duì)每個(gè)方法做什么給出一行描述。有效的 Javadoc 應(yīng)該包括對(duì)下列內(nèi)容的描述:

類如何相互關(guān)聯(lián)
方法如何影響對(duì)象的狀態(tài)
方法如何將出錯(cuò)條件通知它們的調(diào)用者以及它們可能通知什么錯(cuò)誤
類如何處理多線程應(yīng)用程序中的使用
方法的參數(shù)作用域及其返回值的范圍
另外,糟糕的文檔(或甚至更糟糕,沒(méi)有文檔)會(huì)導(dǎo)致優(yōu)秀的代碼不可用或不可重用。通過(guò)在文檔上花一些額外時(shí)間,您將為您的用戶(可能是您自己)避免無(wú)數(shù)的挫折。

參考資料

單擊文章頂部或底部的討論來(lái)參加關(guān)于本文的論壇。

Sun 教程“How to Write Doc Comments for the Javadoc Tool”描述了 Javadoc 的規(guī)則和基本原理。

Josh Bloch 的 Effective Java Programming Language Guide 包含了有關(guān)編寫更好代碼的大量有用提示和指導(dǎo)原則。

Peter Haggar 的文章“Acquire multiple locks in a fixed, global order to prevent deadlock”(developerWorks,2000 年 9 月)描述了一種降低死鎖風(fēng)險(xiǎn)的技術(shù),但這種技術(shù)依靠于對(duì)鎖定行為的有效的文檔。

JContract 是一種強(qiáng)制類契約和類約束的商業(yè)工具。

文章“Exceptional Practices”(JavaWorld,2001 年 8 月)提供了編寫 throws 子句的指導(dǎo)原則。

Jeremy Roschelle 的文章“Doclet your servlet”(JavaWorld,2001 年 3 月)描述了可以怎樣使用定制 doclet 來(lái)為 servlet 更為具體的文檔。

John Farrell 在“Make bad code good”(JavaWorld,2001 年 3 月)中談到了 Javadoc 在重構(gòu) Java 類方面的重要性。

Scott Ambler 為編制方法文檔提供了便捷的檢查表(developerWorks,2001 年 8 月)。

Javadoc doclet API 讓您編寫定制 Javadoc 插件來(lái)生成不同形式的文檔,或甚至從 Javadoc 注釋自動(dòng)生成代碼或模式。

在 developerWorks Java 技術(shù)專區(qū)上查找?guī)装倨?Java 技術(shù)有關(guān)的參考資料。

關(guān)于作者
Brian Goetz 是一名軟件顧問(wèn),在過(guò)去的 15 年里,他一直是一名專業(yè)軟件開發(fā)人員。他是 Quiotix 的首席顧問(wèn),Quiotix 是一家位于加尼福利亞州洛薩圖斯(Los Altos)市的軟件開發(fā)與咨詢公司。在流行的業(yè)界出版物中查閱 Brian 已出版和即將出版的文章。請(qǐng)通過(guò) brian@quiotix.com 和 Brian 聯(lián)系。

發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 阿克陶县| 古蔺县| 京山县| 天水市| 浦县| 玛纳斯县| 元江| 威信县| 沐川县| 登封市| 铁力市| 河间市| 衡水市| 奉节县| 丹江口市| 胶南市| 石林| 东方市| 岢岚县| 沁阳市| 和政县| 嫩江县| 中牟县| 汝州市| 彭州市| 工布江达县| 高安市| 兴宁市| 普安县| 贵南县| 达孜县| 府谷县| 罗平县| 武强县| 民乐县| 华池县| 汉阴县| 淄博市| 南皮县| 孝昌县| 曲松县|