【CSDN 編者按】 這篇文章介紹了編寫整潔的 JAVA 代碼的一些原則和方法,包括遵循標準的項目結構、遵循命名規范、提高代碼可讀性、使用代碼分析工具、編寫有意義的注釋和文檔、保持一致和正確的代碼格式、避免過多參數、編寫單元測試、SOLID 原則、KISS 和 DRY 原則等。文章還給出了一些相關的鏈接和資源,以及作者的個人經驗和建議。
原文鏈接 :https://digma.AI/blog/clean-code-java/
作者 | Digma譯者 | 明明如月
責編 | 夏萌
出品 | CSDN(ID:CSDNnews)
就算是質量欠佳的代碼,如果能夠正常運行,問題或許不大。然而,如果代碼不整潔,這就可能給整個開發團隊帶來困擾—— Uncle Bob。
經過數年科技行業的磨練,特別是在軟件開發領域,我深刻體會到了這樣一個現實:我絕大多數時間都與不同團隊緊密合作,審查他們編寫的代碼。這些年與各種開發者合作的經驗從本質上增進了我對整潔代碼的理解和認知。
“實際上,我們閱讀代碼的時間遠超編寫代碼的時間,這比例甚至超過 10 比 1。我們在致力于編寫新代碼的過程中,會不斷閱讀舊的代碼。……[因此,] 要使代碼易于編寫,首先就要使其易于閱讀。” ——摘自《代碼整潔之道》 (Uncle Bob)。
無論你是資深的軟件開發人員還是新入行者,我相信你都會理解學習和繼承新代碼庫所需付出的艱辛和努力。你需要去理解這個代碼庫的代碼結構、功能、編程語言、使用的庫、框架和其他技術。
當你面對一段陌生的代碼,或者是你自己很久以前寫的代碼,你可能會感到有些難以理解。無論你是想要修復錯誤、增強功能、提升性能,還是加入一個正在進行的項目,代碼的整潔程度都將決定你需要投入的時間和精力。
按照整潔的 Java 代碼原則編寫的代碼可以為你節省大量的時間和減少挫敗感。相反,如果你正在處理混亂的代碼,可能需要花費大量的時間去理解其邏輯、解讀無注釋的部分以及弄明白那些命名不清的變量。
編寫整潔代碼的含義和好處?
整潔的代碼意味著直觀、易讀、可測試和便于理解的代碼。它的特點還包括遵循良好的編程規范和最佳實踐,提高代碼的表達力、簡潔度、組織性和可維護性。此外,整潔的代碼還應避免 bug 、無用的復雜性、代碼異味和重復代碼的問題。
大家稱呼 Robert C. Martin 為 Uncle Bob,他是整潔代碼主題的權威。無論程序員的經驗如何,都可以從他關于代碼整潔的書籍、文章和講座中受益。
他在《代碼整潔之道》書中寫到:
*“雖然糟糕的代碼能運行,如果代碼不整潔,可能會導致開發團隊效率低下。每年,由于代碼質量差而損失的時間和資源是巨大的。然而,這種情況是可以避免的。”
編寫整潔的 Java 代碼的重要性毋庸置疑。以下是整潔代碼帶來的一些直接好處:
- 可維護性 - 整潔的代碼便于維護和更新。
- 調試 - 整潔的代碼減少錯誤,便于隔離和修復問題。
- 可擴展性 - 整潔的代碼具有良好的模塊化、可復用性,能更好地適應未來變化。
- 協作 - 整潔的代碼增進團隊成員之間對代碼的理解。
- 文檔 - 整潔的代碼本身就足夠清晰,降低了額外注釋的需求。
- 效率 - 通過消除重復和無用的復雜性,整潔的代碼能夠提高性能。
- 可讀性 - 整潔的代碼的閱讀性強,有助于降低混淆,增強可維護性。
如何編寫整潔的 Java 代碼
Java 作為一門廣受歡迎的編程語言,具有成熟的特性。許多舊版的 Java 代碼庫 至今仍在運行重要的商業軟件和基礎架構,這些項目始于十多年前,仍服務于大量用戶。
鑒于 Java 代碼庫的長壽的特性,編寫易于后續開發人員維護的整潔 Java 代碼顯得至關重要。下文列舉了一些有助于編寫整潔 Java 代碼的最佳實踐。
1. 遵循標準的項目結構
項目結構涉及如何在項目中組織各類組件,包括 Java 源文件、測試文件、文檔文件、構建文件和配置文件。清晰的項目結構能使代碼庫更易理解、導航和修改。反之,混亂的項目結構可能會在處理大型項目時造成混淆。
雖然 Java 不強制特定的項目結構,但如 Maven 這樣的構建工具為你提供了推薦的項目結構。
src ├── main │ ├── java 應用/庫源碼 │ ├── resources 應用/庫資源 │ ├── filters 資源過濾文件 │ └── webApp Web 應用源碼 │ └── test ├── java 測試源碼 ├── resources 測試資源 └── filters 測試資源過濾文件2. 嚴格遵循 Java 命名規范
Java 命名規范由一系列規則組成,為 Java 開發人員命名變量、包、類和方法提供指導。Java 語言規范包括了這些命名規則。合理的命名能提升代碼的可讀性、一致性和可維護性。
Java 命名規范主要包括:
- 類和接口名以名詞形式,首字母大寫。
- 方法名以動詞形式。
- 變量名需簡短且有意義。
- 包名全小寫。
- 常量名全部大寫。
publicclassPerson{ privateString firstName; privateString lastName;
publicPerson(String firstName, String lastName){ this.firstName = firstName; this.lastName = lastName; }
publicString getFullName{ returnfirstName + " "+ lastName; }
publicstaticfinalintMAX_AGE = 100;
publicbooleanhasValidName{ returnfirstName != null&& lastName != null; }}
更多關于 Java 命名規范的信息,請參閱命名規范。
3.優先考慮可讀性,而非可重用性
雖然可重用性在軟件開發中備受推崇,并且可以減少開發和維護時間,但當我們處理不熟悉的代碼庫時,也可能會引發一些潛在問題。在大型應用程序中,可重用性有時會犧牲可讀性、可用性和可維護性,特別是在設計不當的情況下。隨著代碼邏輯流程變得難以理解,可重用性可能會影響代碼的可讀性。
不易理解的代碼會增加調試難度和維護成本,特別是當試圖吸引新開發人員加入項目時,這可能成為一項挑戰。因此,在開發軟件過程中,請確??勺x性始終處于首要位置,不要盲目追求可重用性。
4. 結合靜態與動態分析工具審查代碼
5. 采用有意義的注釋和文檔
許多開發人員在軟件開發初期,包括我自己,常常會過度使用注釋。不適當的注釋通常暗示代碼編寫的不佳。
在編寫整潔的 Java 代碼過程中,注釋和文檔的合理運用極為重要。雖然理想的代碼應具備自我解釋的特質,有時復雜邏輯卻無法避免。然而,通過策略性地在代碼中加入注釋,可以解釋某些部分背后不太直觀的邏輯。
在 Java 中,開發人員常用兩種類型的注釋:文檔注釋和實現注釋。前者面向代碼庫的使用者,后者則面向開發者。
/*** 代表用于管理用戶資源的 RESTful 控制器類。* 提供了創建、檢索、更新和刪除用戶的相關端點。*/@RestController@RequestMapping( "/api/users") publicclassUserController{/*** 通過 ID 檢索用戶。** @paramid 指定用戶的 ID。 * @return對應 ID 的用戶。 */@GetMapping( "/{id}") publicResponseEntity<User> getUserById( @PathVariable( "id") Longid) { // 實現部分已省略以保持簡潔}
/*** 創建新用戶。** @paramuser 待創建的用戶對象。 * @return新創建的用戶。 */@PostMappingpublicResponseEntity<User> createUser( @RequestBodyUser user) { // 這里是實現部分}
// 代碼的其余部分
6. 一致且得當的代碼格式化:空白和縮進
代碼格式化在個人項目中或處理可能永遠不會由他人維護的代碼時,可能顯得不那么重要。但在團隊環境中,保持一致的代碼格式化和風格則顯得尤為關鍵。
要在團隊中編寫整潔的 Java 代碼,確保團隊和代碼庫中格式化和編碼風格的一致性非常重要??瞻缀涂s進是實現一致編碼風格的關鍵因素。
合適的空白使用,如在運算符、逗號及控制語句周圍,可增強代碼的可讀性。例如,您可以通過空白將代碼劃分為邏輯分組,從而提高可讀性和視覺效果。
縮進是指在循環、方法和控制結構中使用制表符或空格。雖然 Java 沒有強制的縮進規范,但選擇并堅持使用流行的約定是明智的做法。
importorg.springframework.boot.SpringApplication; importorg.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplicationpublicclassMyApplication{
publicstaticvoidmain(String[] args){ SpringApplication.run(MyApplication.class, args);}// 其余代碼部分// ...}
7. 控制方法參數的數量
雖然參數在方法調用中非常重要,但應避免在一個方法中使用過多參數,因為過多的參數數量可能暗示方法處理多于一個關注點,從而違反單一職責原則。
參數過多會降低代碼可讀性,因為參數的類型和意義可能難以跟蹤。為了編寫整潔的 Java 代碼,您應該限制方法參數的數量,并考慮使用對象或數據結構來替換單個參數或將相關參數組織到對象中。
以下是一個具有過多方法參數的 Java 方法示例:
publicvoidprocessOrder( StringcustomerName, StringshippingAddress, StringbillingAddress, StringproductName, int quantity, double price, booleanisExpressShipping) { // 方法實現}下面是通過將相關參數組合到對象中以提高可讀性的重構示例:
publicclassOrder { privateStringcustomerName; privateStringshippingAddress; privateStringbillingAddress; privateStringproductName; privateint quantity; privatedouble price; privatebooleanisExpressShipping;// 構造器、訪問器和修改器// 與訂單相關的其他方法}
publicvoidprocessOrder(Order order) { // 方法實現}
8. 利用單元測試與測試驅動開發(TDD)
在軟件開發領域,單元測試和測試驅動開發(TDD)是不可或缺的實踐手段。單元測試的作用是對各個函數、方法和類的功能進行驗證,保證它們能獨立完成任務。而 TDD 則是一種優先編寫測試再進行開發的方法。
通過采用單元測試和 TDD 方法,您能更加專注于編寫規范、簡潔的 Java 代碼。單元測試可以幫助您及時驗證代碼的正確性,快速發現潛在錯誤,并促使您編寫更模塊化的代碼結構。TDD 方法將為您提供及時的反饋,從而提高您編寫可靠且易維護代碼的信心。
來源:Twitter
9. SOLID 原則
SOLID 原則是由 Robert C. Martin(Uncle Bob)所提出,對于所有開發人員來說都非常重要,它有助于編寫清晰、可維護和可擴展的代碼。
以下將闡述 SOLID 原則如何引導您編寫高質量的 Java 代碼:
單一職責原則(Single Responsibility Principle,SRP):按照此原則,一個類只應擔負一項職責,這有助于保證代碼的簡潔、可讀性和維護性。
開放封閉原則(Open/Closed Principle,OCP):該原則要求類應對擴展開放,對修改封閉,除非進行錯誤修復。這使得您可以在不破壞現有功能的前提下添加新特性。在 Java 中,借助接口或抽象類能實現現有類的功能擴展。
里氏替換原則(Liskov Substitution Principle,LSP):此原則確保您能夠在不影響程序正常運行的情況下,靈活地將超類與其各個子類進行互換。遵循這一原則有助于正確使用繼承,編寫結構松耦合的優雅 Java 代碼。
接口隔離原則(Interface Segregation Principle):此原則鼓勵選擇較小、更具針對性的接口,而非龐大、泛化的接口。這使得您能夠編寫更加模塊化和簡潔的 Java 代碼,確保實現類僅專注于與其相關的功能。
依賴倒置原則(Dependency Inversion Principle,DIP):依賴倒置原則強調降低組件間的緊耦合,推崇依賴于抽象而非具體實現。遵循此原則,您可以通過控制反轉(IoC)和依賴注入實現結構清晰的 Java 代碼。
10. 遵循 KISS 原則和 DRY 原則
KISS 和 DRY 是編程中的基礎原則,對于編寫精煉的 Java 代碼至關重要。DRY 原則主張開發者確保系統中代碼不重復,以此提升代碼的可維護性,并使查找和修復錯誤更為高效。
KISS 原則(Keep It Simple, Stupid)則倡導在軟件設計和開發過程中保持簡潔明了。遵循此原則,你可以消除代碼中的不必要復雜性,從而選擇更易理解的編碼方式。
KISS 原則(Don't Repeat Yourself)有助于增強代碼的可維護性和可讀性,從而提升團隊協作效率,也使新成員更容易融入項目。
11. 遵循一致的源文件結構
Java 的標準源文件包括運行任何 Java 程序所需的關鍵組成部分。為了保持代碼的可讀性,你應當遵循一致的源文件結構。雖然沒有普遍適用的源文件結構,但存在一些廣受推崇的風格指南。
一般來說,Java 的源文件結構應該從包聲明開始,接著是靜態和非靜態的導入聲明,最后定義一個主要的頂級類。
// 類變量privatestaticintcount; privateString name; // 實例變量privateintage; privateList<String> hobbies;// 構造函數publicMyClass( ) { // 構造函數實現}publicMyClass( String name, intage ) { // 構造函數實現}// 方法publicvoidsetName( String name) { // 方法實現}publicString getName( ) { // 方法實現}publicvoidaddHobby( String hobby) { // 方法實現}// 其他方法}
// 額外的類(如果有)classMyStaticClass{ // 類實現}
12. 避免硬編碼
硬編碼是將值直接嵌入到程序源代碼的一種做法,不使用變量表示。對硬編碼的值進行更改必須修改程序源代碼,這樣的做法極大地限制了代碼的重用性和可測試性,并可能引發程序錯誤和代碼重復問題。
為了增強代碼的重用性、可測試性和可維護性,應該避免在程序源代碼中使用硬編碼值。這些都是整潔 Java 代碼的核心特性。您可以通過使用抽象概念,例如常量變量或枚舉,來替換硬編碼的值。
以下是一個包含硬編碼值的 Java 程序示例:
@RestControllerpublicclassHelloWorldController{@GetMapping( "/hello") publicString sayHello { return"Hello, World!"; }@GetMapping( "/user") publicString getUser { // 硬編碼值String username = "John"; int age = 30; return"Username: "+ username + ", Age: "+ age; }// 其他控制器方法}
結論
編寫整潔的 Java 代碼是構建高質量軟件的基礎。
在這篇文章中,我們探討了一些有助于編寫整潔 Java 代碼的主要和常見實踐。然而,值得強調的是,還存在許多其他關鍵因素,包括團隊文化、可用工具和團隊目標。遵循這些原則,你可以構建出可讀、可測試、可擴展和模塊化的代碼。
常見問題解答
整潔代碼是什么?
整潔代碼指的是遵循最佳實踐和編碼規范所編寫的、具有良好可讀性和可維護性的代碼。它不僅易于原作者理解、修改和擴展,同時也方便后續維護的開發人員。
為何編寫整潔代碼很重要?
編寫整潔的代碼可以提高代碼可讀性,增進團隊協作,降低錯誤發生的概率,并且使得代碼維護變得更為便捷。
有哪些工具能夠幫助編寫整潔的 Java 代碼?
有許多輔助工具可供選擇,用于編寫整潔的 Java 代碼,包括靜態代碼分析工具如 SonarQube、FindBugs 和 Digma 等,以及某些集成開發環境(IDE),例如 IntelliJ 和 Eclipse。
我可以從哪些資源中學習到更多關于編寫整潔的 Java 代碼的知識?
有許多博客和在線教程提供相關信息,例如 Baeldung 網站。此外,還有一些值得推薦的書籍,如 Robert C. Martin 的《代碼整潔之道》和 Joshua Bloch 的《Effective Java》。
你認為編寫整潔代碼重要嗎?你還有哪些編寫整潔代碼的經驗?