什麼樣的代碼是好代碼?金秋十月,讀阿里JAVA開發手冊有感而發

前言

最近重溫阿里巴巴Java開發手冊這本書,思考了什麼樣的代碼是好代碼,給你們分享一下個人想法,有哪裏不對,歡迎指出,感激涕零。java

什麼樣的代碼是好代碼?

什麼是好代碼?實現了功能的代碼只是合格的代碼,而真正的好代碼具備如下特色:數據庫

  • 命名易於理解,語義表達清晰而不需人揣摩
  • 代碼邏輯清晰透明,井井有條
  • 代碼格式公整美觀
  • 性能效率高
  • 安全性高

好的命名

好的命名,命名易於理解,語義表達清晰。 是醞釀好代碼的第一步。如下列舉阿里JAVA開發手冊的幾點,都是在強調好的命名,以便於閱讀。編程

抽象類命名使用 Abstract 或 Base 開頭;異常類命名使用 Exception 結尾;測試類 命名以它要測試的類的名稱開始,以 Test 結尾。

理由:你們約定俗成這樣寫,閱讀者一看這個類就知道它是抽象類仍是異常類,豈不美哉。設計模式

推薦指數:五星緩存

杜絕徹底不規範的縮寫,避免望文不知義。

理由:AbstractClass「縮寫」命名成 AbsClass;condition「縮寫」命名成 condi,此類隨意縮寫嚴重下降了代碼的可閱讀性安全

推薦指數:五星性能優化

爲了達到代碼自解釋的目標,任何自定義編程元素在命名時,使用盡可能完整的單詞 組合來表達其意

正例:在 JDK 中,表達原子更新的類名爲:AtomicReferenceFieldUpdater。bash

反例:變量 int a 的隨意命名方式架構

理由:完整的單詞,表達意思更清楚。框架

推薦指數:四星

若是模塊、接口、類、方法使用了設計模式,在命名時需體現出具體模式。

正例:

public class OrderFactory;     
   public class LoginProxy;      
   public class ResourceObserver;
複製代碼

理由:將設計模式體如今名字中,有利於閱讀者快速理解架構設計理念。

推薦指數:四星

不容許任何魔法值(即未經預先定義的常量)直接出如今代碼中。

反例:

String key = "Id#taobao_" + tradeId;      
cache.put(key, value); 
複製代碼

理由:魔法值只有開發者本身知道,或者過一段時間他本身也不知道了。。。還談何維護。。。

推薦指數:五星

枚舉類名建議帶上 Enum 後綴,枚舉成員名稱須要全大寫,單詞間用下劃線隔開。

正例:枚舉名字爲 ProcessStatusEnum 的成員名稱:SUCCESS / UNKNOWN_REASON。

理由:枚舉其實就是特殊的類,域成員均爲常量,且構造方法被默認強制是私有。

推薦指數:三星

清晰的結構,分明的層次,明瞭的邏輯

好的代碼,還表如今清晰的結構,分明的層次,明瞭的邏輯。不只表如今代碼功能層明上,代碼塊、函數各司其職,符合設計模式設計理念,還表如今項目結構輪廓分明。列舉了如下幾點:

不要使用一個常量類維護全部常量,要按常量功能進行歸類,分開維護。

正例:緩存相關常量放在類 CacheConsts 下,系統配置相關常量放在類 ConfigConsts 下。

理由:大而全的常量類,雜亂無章,使用查找功能才能定位到修改的常量,不利於理解和維護。

推薦指數:四星

一個過於冗長的函數或者一段須要註釋才能讓人理解用途的代碼,能夠考慮把它切分紅一個功能明確的函數單元,並定義清晰簡短的函數名,這樣會讓代碼變得更加優雅。

反例:

private String name;
    private Vector<Order> orders = new Vector<Order>();

    public void printOwing() {
        //print banner
        System.out.println("****************");
        System.out.println("*****customer Owes *****");
        System.out.println("****************");

        //calculate totalAmount
        Enumeration env = orders.elements();
        double totalAmount = 0.0;
        while (env.hasMoreElements()) {
            Order order = (Order) env.nextElement();
            totalAmount += order.getAmout();
        }

        //print details
        System.out.println("name:" + name);
        System.out.println("amount:" + totalAmount);
    }

複製代碼

正例:

private String name;
    private Vector<Order> orders = new Vector<Order>();

    public void printOwing() {
        
        //print banner
        printBanner();
        //calculate totalAmount
        double totalAmount = getTotalAmount();
        //print details
        printDetail(totalAmount);
    }

    void printBanner(){
        System.out.println("****************");
        System.out.println("*****customer Owes *****");
        System.out.println("****************");
    }

    double getTotalAmount(){
        Enumeration env = orders.elements();
        double totalAmount = 0.0;
        while (env.hasMoreElements()) {
            Order order = (Order) env.nextElement();
            totalAmount += order.getAmout();
        }
        return totalAmount;
    }

    void printDetail(double totalAmount){
        System.out.println("name:" + name);
        System.out.println("amount:" + totalAmount);
    }
複製代碼

推薦指數:四星

使用多態或者適當的設計模式替代複雜冗長的if...else/switch

好比:

int getArea() {
        switch (shape){
        case SHAPE.CIRCLE:
        return 3.14 * _r * _r; break;
        case SHAPE.RECTANGEL;
        return width *,heigth;
        }
    }
複製代碼

使用多態後:

class Shape {
        int getArea(){};
    }

    class Circle extends Shape {
        int getArea() {
            return 3.14 * r * r; 
        }
    }

    class Rectangel extends Shape {
        int getArea() {
            return width * heigth;
        }
    }

複製代碼

推薦指數:三星

項目結構須要輪廓分明,簡言之分包名劃分清楚。

說明:以下爲rocketMq源碼項目結構圖。

推薦指數:四星

代碼格式優雅

優雅的代碼格式,是使代碼有個好看的皮囊,因此平時寫代碼注意用快捷鍵優化一下格式。

大括號的使用約定。若是是大括號內爲空,則簡潔地寫成{}便可,不須要換行;若是 是非空代碼塊則

  • 1) 左大括號前不換行。
  • 2) 左大括號後換行。
  • 3) 右大括號前換行。
  • 4) 右大括號後還有 else 等代碼則不換行;表示終止的右大括號後必須換行。

推薦指數:五星

左小括號和字符之間不出現空格;一樣,右小括號和字符之間也不出現空格;而左大 括號前須要空格

反例:

if (空格 a == b 空格)
複製代碼

推薦指數:五星

不一樣邏輯、不一樣語義、不一樣業務的代碼之間插入一個空行分隔開來以提高可讀性。

說明:任何情形,沒有必要插入多個空行進行隔開。

推薦指數:四星

效率性

單單有好看的皮囊固然仍是不夠,還要持久實用呢,才能稱得上好腰桿代碼。阿里開發手冊如下幾點,都有助於提升代碼性能。固然,除了這些,還有平常開發中,哪些代碼流程是否能夠優化,哪些接口是否調用多了,那些代碼是否是沒用到。總之,這個要看本身總結與積累。

集合初始化時,指定集合初始值大小。

說明:HashMap 使用 HashMap(int initialCapacity) 初始化。

正例:initialCapacity = (須要存儲的元素個數 / 負載因子) + 1。注意負載因子(即loader factor)默認爲 0.75,若是暫時沒法肯定初始值大小,請設置爲 16(即默認值)。

反例:HashMap 須要放置 1024 個元素,因爲沒有設置容量初始大小,隨着元素不斷增長,容 量 7 次被迫擴大,resize 須要重建 hash 表,嚴重影響性能。

推薦指數:四星

線程資源必須經過線程池提供,不容許在應用中自行顯式建立線程。

說明:使用線程池的好處是減小在建立和銷燬線程上所消耗的時間以及系統資源的開銷,解決 資源不足的問題。若是不使用線程池,有可能形成系統建立大量同類線程而致使消耗完內存或 者「過分切換」的問題。

對於接口性能,能夠考慮緩存,分批,SQl索引等這些手段。

說明:以上幾點,是針對代碼塊的性能優化。對於接口,跟SQL有關的話,考慮添加索引等手段,若是涉及大量數據,能夠考慮分批思想,還能夠考慮添加緩存,冷熱數據區分等。

安全性

安全性對於好代碼的判斷標準,具備一票否決權。對於這一點,咱們平時能夠積累,避開如下一些雷區外,有時間能夠看一些經常使用框架,中間件的源碼,如rocketMq,sring,jdk源碼等,學習裏面一些寫法,以及避開可能的坑。

Object 的 equals 方法容易拋空指針異常,應使用常量或肯定有值的對象來調用 equals

正例: "test".equals(object);

反例:object.equals("test");

說明:推薦使用 java.util.Objects#equals(JDK7 引入的工具類)

推薦指數:五星。

ArrayList的subList結果不可強轉成ArrayList,不然會拋出ClassCastException 異常,即 java.util.RandomAccessSubList cannot be cast to java.util.ArrayList

理由:subList 返回的是 ArrayList 的內部類 SubList,並非 ArrayList 而是 ArrayList 的一個視圖,對於 SubList 子列表的全部操做最終會反映到原列表上

推薦指數:五星。

用戶請求傳入的任何參數必須作有效性驗證。

說明:忽略參數校驗可能致使:

  • page size 過大致使內存溢出
  • 惡意 order by 致使數據庫慢查詢
  • 任意重定向
  • SQL 注入
  • 反序列化注入
  • 正則輸入源串拒絕服務 ReDoS

說明:Java 代碼用正則來驗證客戶端的輸入,有些正則寫法驗證普通用戶輸入沒有問題, 可是若是攻擊人員使用的是特殊構造的字符串來驗證,有可能致使死循環的結果。

推薦指數:五星。

慎用無界隊列線程池,如newFixedThreadPool線程池致使的內存飆升。

說明:newFixedThreadPool線程池可能致使的內存飆升問題,是由於它使用了無界隊列。因此這些點須要咱們積累以及看一下經常使用類的源碼,如線程池,AQS等等。

推薦指數:三星。

總結

因此具備如下幾點特性的代碼,就是好代碼

  • 好的命名
  • 清晰的結構
  • 優雅的格式
  • 性能好,效率高
  • 安全穩定

平時咱們能夠多點積累,看書,看源碼,着這裏給你們推薦幾本書

  • 阿里巴巴Java開發書冊》
  • 《重構 改善既有代碼的設計》
  • 《Spring源碼深度解析》
  • 《HeadFirst設計模式》

參考與感謝

  • 《阿里巴巴Java開發書冊》
  • 《重構 改善既有代碼的設計》

我的公衆號

  • 若是你是個愛學習的好孩子,能夠關注我公衆號,一塊兒學習討論。
  • 若是你以爲本文有哪些不正確的地方,能夠評論,也能夠關注我公衆號,私聊我,你們一塊兒學習進步哈。
相關文章
相關標籤/搜索