Java語言按照Javadoc注釋約定采用了一種集成的方法來進行API文檔編制
Javadoc工具可以幫助生成好的API文檔
然而大多數Java API文檔卻很糟糕
因為它是源代碼的一部分
所以 API 的文檔編制職責最終還是落到了工程師身上
在本文中
Brian 對 Java 文檔編制實踐的當前狀態進行了嚴厲的批評
同時提供了一些關於如何編寫更有用的 Javadoc 的准則
對於大多數 Java 類庫來說
Javadoc 是唯一的文檔
而且
除了商業軟件組件之外
許多 Java 類不會用到 Javadoc
雖然 Javadoc 作為 API 參考工具很出色
但對於了解類庫是如何組織的和應該如何使用它來說
它卻是一種十分差勁的方法
並且即便用了 Javadoc
它通常只包含有關方法完成了什麼的最基本信息
而忽略了諸如錯誤處理
參數及返回值的作用域和范圍
線程安全
鎖定行為
前置條件
後置條件
不變條件或副作用之類的重要特性
向 Javadoc 學習
對於包括大多數開放源碼包和大多數內部開發的組件在內的許多Java工具而言
實際情況是
包括Javadoc在內
幾乎所有類庫或組件都不具有有效的文檔
這就意味著開發人員要從Javadoc學習使用工具
而且我們應該考慮根據這一現實組織我們的Javadoc
我經常開玩笑說
現在
Java程序員需要具備的最重要的技能之一是熟練地使用Google和Javadoc來對那些文檔編制得十分糟糕的 API 進行
逆向工程
這可能是真的
但卻並不十分好笑
大多數 Java 包都有某種
根
對象
它是在得到該工具內的任何其它對象之前
必須創建的第一個對象
在 JNDI中
該根對象是Context
而在JMS和JDBC中
它是Connection
如果有人告訴您JDBC中的基礎對象是 Connection
以及如何獲得這一對象
那麼接著您很可能會從 Javadoc 中通過仔細察看 Javadoc 中可用的方法列表找到如何創建並執行 Statement
以及如何迭代生成的 ResultSet
但您如何知道獲得 Connection 是您的第一步呢?Javadoc 在包內按照字母順序組織類
在類中按照字母順序組織方法
遺憾的是
Javadoc 中沒有神奇的
從這裡開始(Start Here)
記號把讀者帶到浏覽 API 的邏輯開始位置
包描述
最接近
從這裡開始
記號的是包描述
但它卻很少得到有效的使用
如果將文件 l 與源代碼一起放在一個包中
那麼標准的 doclet 會將已生成的 l 文件中的內容連同類列表一起放在該包內
遺憾的是
生成我們都很熟悉的 HTML 文檔的標准 doclet 卻無法使包描述易於找到
如果您單擊左上窗格中的某個包
那麼這會在左下窗格中產生方法列表
但並不會在主窗格中產生包的摘要 — 必須單擊左下窗格中的包名稱來查看摘要
但不要緊
畢竟大多數包並沒有包描述
包文檔是一個放置
從這裡開始
文檔的極好的地方
這一文檔用來概述包做什麼
主要摘要是什麼以及從何處開始浏覽包的 Javadoc
類文檔
除包文檔之外
特定於類的文檔對於幫助用戶徹底了解新工具也能起到重要的作用
類文檔當然應該包括此特定類做什麼的描述
但還應該描述該類與包中的其它類如何關聯
特別是要標識任何與該類相關的工廠類
例如
JDBC 中的 Statement 類文檔應該說明
Statement 是通過 Connection 類的 createStatement() 方法獲得的
這樣
如果一個新用戶偶然進入 Statement 頁面
那麼他會發現首先他需要獲得 Connection
對每個類都應用這一約定的包會迅速為用戶指出根對象
用戶因而能夠得心應手
因為 Javadoc 是圍繞對特定類進行文檔編制而設計的
因此在 Javadoc 中通常沒有明顯的位置來放置演示幾個相關類一起使用的示例代碼
但由於一味地側重於特定類或方法的文檔編制
我們失去了討論如何組合包中內容的機會
如果對於根對象
在包文檔或類文檔中有一個演示一些基本用法的簡單代碼示例
則對於許多用戶來說
將是非常有用的
例如
Connection 類文檔可以有一個簡單示例
該示例獲取連接
創建預編譯語句
執行該語句並迭代結果集
從技術上說
這可能不屬於 Connection 頁面
因為它還描述了包中的其它類
然而
尤其是當結合了上面那種引用當前類所依賴的類的技術時
用戶才能非常迅速地找到獲取簡單的實用示例的途徑
不管類的組織方式如何
糟糕的文檔=糟糕的代碼
對於大多數 Java 類庫來說
除了那些作為打包組件出售的商業產品之外
要麼沒有 Javadoc
要麼非常糟糕
由於存在的事實是對於大多數包來說
Javadoc 是我們擁有的唯一文檔
這基本上意味著使我們自己陷入了這樣的困境
除了作者之外
其他人沒法使用我們的大部分代碼——如果不付出重大的
考古
一樣的努力
至少會這樣
由於文檔現在是代碼的一部分
因此我認為是軟件工程社區形成一個共識的時候了
這就是
即使代碼很出色
如果文檔很糟糕
也應該被認為是差勁的代碼
因為不能有效地重用
單元測試不久前還聲譽不佳
只是到了最近它才受到了許多工程師的青睐
就和它一樣
為了改善我們生產的軟件的可靠性和可重用性
API 文檔也必須成為開發過程的一個集成部分
編寫Javadoc就是某種形式的代碼檢查
編寫合理的Javadoc也會產生副作用
它迫使我們進行某種形式的代碼檢查
來研究類的體系結構和它們之間的關系
如果單個包
類或方法很難編制文檔
那麼或許可以嘗試同時對多個包
類或方法進行文檔編制
這應該是個提示
即可能它需要重新設計
文檔的自我檢查方面使得某些方面更加重要
即在開發過程中盡早編寫Javadoc
然後隨著代碼的不斷開發
定期對其進行檢查
而不是僅僅等待代碼完成再編寫文檔(如果有剩余時間的話)
後一種策略十分常見
它將編寫文檔拖到項目最後
而那時時間安排十分緊張
開發人員的壓力也很大
結果再常見不過了
就是那種一文不值的文檔
它只提供了
文檔假象
用戶真正需要的是了解該類的工作原理
而該文檔卻沒有提供任何這樣的信息
清單
典型的一文不值的 Javadoc
/**
* Represents a command history
*/
public class CommandHistory {
/**
* Get the command history for a given user
*/
public static CommandHistory getCommandHistory(String user) {
}
}
什麼是好的文檔
那麼好的文檔包括哪些內容呢?
上面描述的組織技術(在類描述中引用相關類或工廠類
也包括了包概述和代碼樣本)是形成優秀文檔的好開端
它有助於新用戶使用 Javadoc 了解新工具
但體系結構的概述只完成了任務的一半
另一半則是詳細地解釋方法做什麼和不做什麼
在什麼條件下運行以及它們如何處理錯誤條件
大多數 Javadoc 都沒有完全提供所需的信息
即便是那些充分描述了方法在期望情況下的行為的 Javadoc 也是如此
這些缺少的信息包括
· 方法如何處理錯誤條件或不合要求的輸入
· 如何將錯誤條件傳回給調用者
· 可能會拋出哪個特定異常的子類
· 哪些值對於輸入是有效的
· 類不變條件
方法前置條件或方法後置條件
· 副作用
· 在方法之間是否有重要聯接
· 類如何處理多個線程同時訪問一個實例的情況
Javadoc 約定提供了 @param 標記
它讓我們除了能夠對參數的名稱和類型編制文檔之外
還可以對其意義編制文檔
然而
並不是所有的方法都能很好地接受參數的任何值
例如
雖然可以合法地向任何獲取對象參數的方法傳遞空值(null)而不違反類型檢查規則
但並不是所有的方法都能在傳入空值時正常工作
Javadoc 應該顯式地描述有效的參數范圍
如果它希望某個參數非 null
那麼它應該這樣描述
而如果它期望參數值在某個范圍內
例如某種長度的字符串或大於
的整數
那麼它也應該那樣描述
並非所有方法都仔細檢查其參數的有效性
不進行有效性檢查也沒有編制關於可接受的輸入范圍的文檔
這二者的結合為災難埋下了隱患
返回代碼
Javadoc 使得描述返回值的意義變得很容易
但正如方法參數一樣
@return 標記應該包括對可能返回的值范圍的詳細描述
對於對象取值的返回類型而言
它會返回空值嗎?對於整數取值的返回類型而言
結果會限制在一個已知值或非負值的集合上嗎?任何返回代碼都有特殊意義嗎
例如從 java
io
InputStream
read() 返回
表示文件結束符?返回代碼會被用來表示例如如果無法找到表項則返回空值那樣的錯誤條件嗎?
異常
標准 doclet 復制方法的 throws 子句
但 Javadoc @throws 標記應該更為具體
例如
NoSuchFileException 是 IOException 的子類
但 java
io 中的大多數方法卻只被聲明為拋出 IOException
然而
方法可能獨立於其它 IOException 而拋出 NoSuchFileException
這是調用者要了解的很有用的事實 — 它應該被包括在 Javadoc 中
還應該指出拋出各種異常類的實際錯誤條件
以便調用者知道在給定異常被拋出時該采取什麼糾正措施
應該用 @throws 標記對方法可能拋出的每個經檢查的或未經檢查的異常編制文檔
並對引發拋出異常的條件編制文檔
前置條件
後置條件和不變條件
當然
您應該對方法對對象狀態的影響編制文檔
但您可能需要編制得更詳細一些
描述方法的前置條件
後置條件和類不變條件
前置條件是在調用方法前對對象狀態的約束
例如
調用 Iterator
next() 的前置條件是 hasMore() 為真
後置條件是方法調用完成後對對象狀態的約束
例如在調用 add() 之後 List 不能為空
不變條件是對對象狀態的一種約束
它保證該狀態始終
From:http://tw.wingwit.com/Article/program/Java/JSP/201311/19207.html