Java 介面規範與最佳實踐
-
可理解
-
文件完善
-
格式統一:這裡涉及很多方面,包括:介面返回型別、命名規則以及引數順序
- 在我們所有的API方法中,要麼是全是
getXYZ()
格式,要麼全是xyz()
,最好不要兩種格式都有。 - 假設我們有方法過載,原始方法接受引數
Object...
,過載方法接受引數為Collection<? extends Object>
,那麼,過載方法不能部分可見
- 在我們所有的API方法中,要麼是全是
-
恰到好處的適用:作為一名開發人員,很自然的一種本能就是儘可能的開發提供大而全的服務介面,但這樣做可能會帶來兩個問題:1. 介面過於笨重,介面呼叫方可能需要額外消化一些不必要的業務邏輯來理解介面實際含義。2. 介面暴露越多,維護負擔越重。因此,所謂恰到好處的適用
- 介面應功能單一,並且能正確響應
- 瞭解介面潛在使用者及目標
-
一定範圍、時期的使用受限:我們都知道開發介面非常容易,但事情遠非一蹴而就那麼簡單,介面背後帶來的是服務承諾。介面的服務成本依賴於很多因素:專案的實際情況以及社群本身,比如,有些專案可能非常樂於變更,但有些專案(比如JDK)則期待儘量保持穩定,這是兩種極端狀態,但,對於絕大部分專案來說,基本上都處於中間狀態,慣例做法是通過一種語義化的版本管理方式實現介面的持續演變,即在介面從主版本更新刪除之前,首先進行廢棄處理(即我們常見的deprecate標識)。對於某些少部分專案來說,他們處理的方式更加多樣,專案中會包含多種介面標識:比如:實驗性版本的、Beta版本的、預覽功能性的,這麼做的目的是在最終介面確定之前,可以真實的收到各種版本介面的真實使用反饋,通常做法是在這些不同的版本介面上新增
@Deprecated
-
可變的:對於我們對外暴露的每一個介面,這都是一種服務承諾,既然是承諾,那麼都有可能未來讓我們自己為難或者尷尬的境地,所以,我們必須以發展前瞻的眼光來審視未來可能的SDK版本更新中更廣泛的上下文環境中對介面所帶來的影響。
-
防止資訊洩漏:避免介面實現類或者外部依賴類通過公共介面暴露出去(所謂暴露出去可能有兩種方式:作為返回型別、作為引數型別),通常有以下兩種方式來避免資訊洩露:
- 所有實現類均置於
impl
包中,此包下的所有類均不會出現在JavaDoc
中,如果介面基於JDK1.9或者以上的版本開發,可以通過模組的方式排除目標類集合 - 確保所有實現類的訪問修飾符為
package-private
,即類定義不包含任何訪問修飾符。
- 所有實現類均置於
-
正確理解protected含義:Java中的
protected
關鍵字經常被誤用或者說濫用,簡單來說,protected
主要用於子類之間,而public
則主要用於對外介面。事實上protected
關鍵字會影響介面類的行為,進而導致本不應暴露的內部私有方法暴露成protected
或者public
型別。 -
刻意繼承:當我們在開發一個介面時,我們必須在功能性、靈活性和未來的可發展性、可持續性之間作一個平衡,一種常見的做法是使用
final
關鍵字,一旦標識一個方法或者類為final
型別,我們就是要明確的告訴開發人員,不要去擴充套件或者重寫這些特殊的類或者方法。final
關鍵字對我們非常有用,畢竟我們的介面並非十全十美,與其受困於在老的版本中不停的解決問題,還不如另闢蹊徑升級介面補丁,這樣的話,我們只會引入新的問題,理想情況下,當介面呼叫方發現final
標識,他們甚至可以直接與介面方直接溝通討論,直至達到更加完美的介面服務方案,final
關鍵字可以在後續的正式釋出版本中剔除,但不建議在已經發布的介面中使用final
關鍵字。 -
向後相容:在我們的日常介面實踐中,當我們遇見新的需求或者問題時,好的做法是新增一個介面,但不推薦刪除或者修改現有的介面。這麼做的主要目的是向後相容,這也很容易理解,當我們刪除或者修改一個現有介面時,在使用者升級至下個釋出之前,我們其實就隱含帶來了破壞使用者原有程式碼正常呼叫的風險。但有時候,我們需要實現介面向後不相容(比如,原有介面設計錯誤),一般我們可以使用
@Deprecated
,但通常的做法是使用semantic versioning策略。 -
正確的使用Optional:JDK1.8引入的
Optional
關鍵字為我們減少NPE錯誤提供了一種可能,當方法返回為Optional
它可以確保返回值不為NULL,那麼在這種場景下,就需要由呼叫方來確認返回值中是否包含元素或者為空。但注意:- 不要返回
Optional<Collection<T>>
,這種可以簡潔的以Collection<T>
形式來表示 - 不要在返回型別為
Optional
的方法中返回null
- 不要返回
-
不要返回null值:billion-dollar mistake,在Java中較之null返回值,針對不同的返回型別,我們都有更好的選擇:
RETURN TYPE | NON-NULL RETURN VALUE |
---|---|
String | “” (An empty string) |
List / Set Map / Iterator | Use the Collections class, e.g. Collections.emptyList() |
Stream | Stream.empty() |
Array | Return an empty, zero-length array |
All other types | Consider using Optional (but read the Optional section below first) |