編寫高質量的代碼(2)


編碼前全面考慮所有可能的輸入,確保寫出的代碼在完成了基本功能之外,還考慮了邊界條件,並做好了錯誤處理。只要全面考慮到這三方面的代碼纔是完整的代碼。

要重視代碼的魯棒性,確保自己寫出的程序不會輕易崩潰。平時在寫代碼時,養成防禦式編程的習慣,在函數入口判斷輸入是否有效並對各種輸入做好相應的處理

目的:提高代碼可讀性、維護性,降低bug,提高程序性能,最終保證代碼質量

建議+案例+原因;

checklist

 

閱讀代碼:瞭解其運行機制、內部結構;學習其技巧。

閱讀代碼可作爲學習程序設計的方法。

花時間經常閱讀高質量的代碼——>提高編寫代碼的能力!“爲什麼要這樣寫?”

提高自身的開發和設計能力——>廣泛閱讀現有的構架,瞭解它們是如何組織的。

 

編寫的代碼總是存在改進的空間。

編碼時就要考慮使之易於閱讀。

 

分析設計良好的軟件系統的內部系統可以學到新的構架模式、數據結構、編碼方法、算法、風格和文檔規範、應用程序編程接口、甚至新的計算機語言。

 

從小型的程序開始閱讀,通過運行程序來得到反饋。主動修改代碼來檢驗對代碼的理解是否正確。要從小的改動做起,逐漸增大它們的範圍。

考慮如何改進它?——更好的設計、算法或功能。爲代碼編寫文檔。

 

自身價值的體現——不是掌握了多少知識,而是體現在我們創造的系統上

 

物理模型

 

與代碼相關的概念:

編程構造(基本編程元素)、數據類型、數據結構、控制流程、項目組織、代碼規範、文檔和構架。

 

在軟件系統的工作投入中,40%~70%是用在系統首次編寫完成之後。

 

 

1、原則

a、OCP開放-關閉原則:指導封裝;

b、SRP單一職責原則:粒度控制;

c、DIP依賴倒置原則:

d、LSP里氏替換原則:指導多態;

e、ISP接口隔離原則:粒度控制;

 

2、避免錯誤

(1)合理使用註釋

同步修改註釋,和代碼保持一致;

註釋加在接口上;


(2)避免空指針:調用對象的方法,一定要明確該對象是否會空,不能確定時要判斷!開發者常常自以爲該對象不爲null,而沒有去看代碼的實現或沒有思考周全,漏掉了一些分支情況。

對於允許其值爲null的變量,在對其操作前,需要預先判斷其是否爲null。


(3)Serializable對象

所有Serializable對象必須設置serialVersionUID,除非特殊情況。


序列化是爲了保持版本的兼容性,即在版本升級時反序列化仍保持對象的唯一性。


(4)在finally中釋放資源——數據庫連接、打開的文件等。


3、維護性

(1)重複代碼:

a、保持類和方法職責單一。(粒度劃分)

b、儘量利用框架提供的功能。

c、採用合理的設計模式。


(2)異常處理:打印合理的異常。

a、只捕獲對自己有意義的特定異常,一般不要捕獲Exception異常;

b、拋出對自己無意義的異常,並保留原始的異常對象(嵌套異常),並描述異常的原因;

如:

try{

          createMember();

catch(SQLException e) {

           throw  new MemberCreationException("Failed to create member", e);

}

c、所有異常要麼捕獲、要麼拋出、要麼記錄。


(3)常量定義(什麼時候定義常量?在哪裏定義?如何定義?

a、多次引用的字符串和數字需要定義常量;

b、根據引用的範圍(同一個類、不同類):

類中;

單獨的常量類或接口;

c、常量定義處需要詳細的註釋;


(4)在配置文件中指定字符集編碼,由框架來轉換字符串避免在代碼中假設用戶和系統的字符集編碼

如:

下列代碼“假設”了用戶的字符集編碼:

// 如果源代碼是以GBK編譯的,那麼該URL也是GBK編碼的,然而用戶可能使用UTF-8編碼

response.sendRedirect(http://localhost/mypage.htm?p=中文); 

 

//總是以GBK輸出頁面

response.setContentType("text/html; charset=GBK");

 

 

下列代碼的結果依賴於操作系統的字符集編碼:

Stringurl =URLEncoder.encode(str);            // str轉換成URL兼容的格式byte[] 


bytes =str.getBytes();                  // string轉成bytes

Stringstr = new String(bytes);                //bytes轉成string

 

(5)避免硬編碼URL、文件路徑:因爲URL、文件路徑等資源的不確定性,應避免在程序中硬編碼這些內容。

 

4、性能

(1)拼裝字符串:用StringBuffer,而不用"+"或"+="來拼裝大量字符串。可以使用StringBuilder來代替StringBuffer。前者是後者的非同步版本,性能更優。

如:StringBuffer sb = new StringBuffer();

for(int i=0; i<100; i++) {

    sb.append("aa").append(" ");

}

String str = sb.toString();

 

(2)預編譯正則表達式

利用java.util.regex.*:

Pattern pattern = Pattern.compile("^\\d+$");

Matcher matcher = pattern.matcher(str);

if(matcher.matches()) {

}

而不是:

if(str.matches("^\\d+$")) {

}

 

(3)日誌輸出:要明白什麼時候需要打印日誌,採用什麼級別打印日誌。

不要以System.out和System.err來輸出信息,而應該採用框架提供的Logging API。

在生產環境中必須關閉DEBUG日誌。

 

正式使用日誌時,儘量不要使用warn級別,避免日誌文件臃腫。


(4)批量操作SQL

批量插入、更新操作:

PreparedStatement ps = conn.preparedStatement("insert into test_table(...) values(?,?,...)");

ps.setString(1,"aaa")

ps.addBatch();

.....

 

ps.executeBatch();

 

(5)線程同步:避免長時間地鎖定線程。

 

4、開發技巧

(1)儘可能使用泛型而不是直接使用集合類:將運行時錯誤轉化爲編譯時錯誤。

 

(2)開發小工具

Findbugs:

Relo:幫助開發人員研究大型代碼庫的好工具,它能一步步的跟蹤你所展開的代碼包,並快速生成類似UML的類圖。

 

(3)閱讀源碼:JDK、Spring等。

 

5、TIPS

(1)不要往cookie中設置過多過大的數據。

 

(2)任何數據放入cache中都要考覈這些數據是否符合三個指標(更新頻率、訪問量、命中率)。要把更新不頻繁、訪問量高、命中率高的數據放入cache中。同時慎用OSCache的文件持久化。

(3)在使用SQL語句時一定要清楚它的執行頻率

 

(4)一條正確的SQL語句隨着時間的推移,數據量越來越大,也可能不合適了。在使用SQL語句時一定要弄清楚它的數據量的增長

 

(5)如何區分好代碼與壞代碼

 

(6)閱讀代碼的方法

 

6、PS

(1)《effective java》、《重構》

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章