java代碼開發規范


一  編碼規范

1.1      命名規范

 

  1. 代碼中的命名均不能以特殊字符(如下划線、$#符號)開始或結束。

 反例: _name / #Object

2. 代碼中的命名嚴禁使用拼音與英文混合的方式,更不允許直接使用中文的方式。

反例: toubao / lipei。

3. 類名使用UpperCamelCase風格,必須遵從駝峰形式。

正例:CommonUtils / BaseVo

4. 方法名、參數名、成員變量、局部變量都統一使用lowerCamelCase風格,必須遵從駝峰形式。

正例: orderService / getOrderService()

5. 常量命名全部大寫,單詞間用下划線隔開,力求語義表達完整清楚,不要嫌名字長。

正例: ZK_CONFIG_ROOTNODE

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

7. 包名使用com.hetai.服務名.分層名。

正例: oauth系統的DAO, com.hetai.oauth.dao

8. 如果使用到了設計模式或具有明確職責,建議在類名中體現出具體模式或職責。

正例:ExecutorFactory / AbstractProducer

        9. 各分層都需要接口和實現類,實現類用Impl作后綴與接口區別。

正例:OrderServiceImpl實現OrderService接口。

        10. 枚舉類名建議帶上Enum后綴,枚舉成員名稱需要全大寫,單詞間用下划線隔開。

正例:枚舉名字:PolicyIdTypeEnum,成員名稱:ID_CARD/ PASSPORT。

11. 各層方法命名規范: 1) 查詢的方法用get/ query做前綴。

2) 插入的方法用add 或insert做前綴。

3) 刪除的方法用remove 或delete做前綴。

4) 修改的方法用modify/ update做前綴。

5) 獲取多個對象的方法用List做結尾。

6)  獲取統計值的方法用Count做結尾。

12. 全局常量類名建議“模塊名Constant”。

正例:枚舉名字:OrderConstant / CommonConstants。

        13. 不要出現任何魔法值(即未經定義的常量)直接出現在代碼中,應作常量聲明。

反例: return "UNDERWRITE_RESULT_" + order_no;

1.2      OOP規范

 

  1. 對外暴露的接口簽名,原則上不允許修改方法簽名,避免對接口調用方產生影響。
  2. 序列化類新增屬性時,請不要修改serialVersionUID字段,避免反序列失敗;如果完全不兼容升級,避免反序列化混亂,那么請修改serialVersionUID值。

說明:注意serialVersionUID不一致會拋出序列化運行時異常。

  1. POJO類必須寫toString方法。使用IDE的中工具:source> generate toString時,如果繼承了另一個POJO類,注意在前面加一下super.toString。

說明:在方法執行拋出異常時,可以直接調用POJO的toString()方法打印其屬性值,便於排查問題。

  1. 當一個類有多個構造方法,或者多個同名方法,這些方法應該按順序放置在一起,便於閱讀。
  2. POJO類中變量需要有get/set方法,通過使用IDE Generate自動生成。
  3. 循環體內字符串的聯接方式,使用StringBuilder的append方法進行擴展。
  4. final可提高程序響應效率,聲明成final的情況: 1) 不需要重新賦值的變量,包括類屬性、局部變量。

2) 對象參數前加final,表示不允許修改引用的指向。

3) 類方法確定不允許被重寫。

  1. 慎用Object的clone方法來拷貝對象。 說明:對象的clone方法默認是淺拷貝,若想實現深拷貝需要重寫clone方法實現屬性對象的拷貝
  2. 不要在foreach循環里進行元素的remove/add操作。remove元素請使用Iterator方式,如果並發操作,需要對Iterator對象加鎖

10. 使用entrySet遍歷Map類集合KV,而不是keySet方式進行遍歷。 說明:keySet其實是遍歷了2次,一次是轉為Iterator對象,另一次是從hashMap中取出key所對應的value。而entrySet只是遍歷了一次就把key和value都放到了entry中,效率更高。如果是JDK8,使用Map.foreach方法。

正例:values()返回的是V值集合,是一個list集合對象;keySet()返回的是K值集合,是一個Set集合對象;entrySet()返回的是K-V值組合集合

11. 高度注意Map類集合K/V能不能存儲null值的情況,如下表格:

集合類

Key

Value

Super

說明

Hashtable

不允許為null

不允許為null

Dictionary

線程安全

ConcurrentHashMap

不允許為null

不允許為null

AbstractMap

分段鎖技術

TreeMap

不允許為null

允許為null

AbstractMap

線程不安全

HashMap

允許為null

允許為null

AbstractMap

線程不安全

 

1.3      控制規范

 

  1. 在一個switch塊內,每個case要么通過break/return等來終止,要么注釋說明程序將繼續執行到哪一個case為止;

在一個switch塊內,都必須包含一個default語句並且放在最后,即使它什么代碼也沒有。

  1. 在if/else/for/while/do語句中必須使用大括號,即使只有一行代碼,避免使用下面的形式:if (condition) statements;
  2. 除常用方法(如getXxx/isXxx)等外,不要在條件判斷中執行其它復雜的語句,將復雜邏輯判斷的結果賦值給一個有意義的布爾變量名,以提高可讀性。
  3. 循環體中的語句要考量性能,以下操作盡量移至循環體外處理,如定義對象、變量、獲取數據庫連接,進行不必要的try-catch操作(這個try-catch是否可以移至循環體外)。
  4. 方法中需要進行參數校驗的場景:    1)調用頻次低的方法。

2) 執行時間開銷很大的方法,參數校驗時間幾乎可以忽略不計,但如果因為參數錯誤導致中間執行回退,或者錯誤,那得不償失。

3) 需要極高穩定性和可用性的方法。

4) 對外提供的開放接口,不管是RPC/API/HTTP接口。

5) 敏感權限入口。

1.4     格式規范

 

代碼格式化參考<<eclipse編碼規范約定>>

1.5      並發規范

 

  1. 獲取單例對象需要保證線程安全,其中的方法也要保證線程安全。 說明:資源驅動類、工具類、單例工廠類都需要注意;
  2. 創建線程或線程池時請指定有意義的線程名稱,方便出錯時回溯;
  3. 線程資源必須通過線程池提供,不允許在應用中自行顯式創建線程;
  4. SimpleDateFormat 是線程不安全的類,一般不要定義為static變量,如果定義為static,必須加鎖,或者使用DateUtils工具類;

正例:注意線程安全,使用DateUtils。亦推薦如下處理:

private static final ThreadLocal<DateFormat> df = new ThreadLocal<DateFormat>() {

@Override

protected DateFormat initialValue() {

return new SimpleDateFormat("yyyy-MM-dd");

}

};

說明:如果是JDK8的應用,可以使用Instant代替Date,LocalDateTime代替Calendar,DateTimeFormatter代替Simpledateformatter,官方給出的解釋:simple beautiful strong immutable thread-safe。

  1. 高並發時,同步調用應該去考量鎖的性能損耗。能用無鎖數據結構,就不要用鎖;能鎖區塊,就不要鎖整個方法體;能用對象鎖,就不要用類鎖;
  2. 對多個資源、數據庫表、對象同時加鎖時,需要保持一致的加鎖順序,否則可能會造成死鎖。 說明:線程一需要對表A、B、C依次全部加鎖后才可以進行更新操作,那么線程二的加鎖順序也必須是A、B、C,否則可能出現死鎖;
  3. 使用CountDownLatch進行異步轉同步操作,每個線程退出前必須調用countDown方法,線程執行代碼注意catch異常,確保countDown方法可以執行,避免主線程無法執行至await方法,直到超時才返回結果。 說明:注意,子線程拋出異常堆棧,不能在主線程try-catch到;
  4. 避免Random實例被多線程使用,雖然共享該實例是線程安全的,但會因競爭同一seed 導致的性能下降;

說明:Random實例包括java.util.Random 的實例或者 Math.random()實例。 正例:在JDK7之后,可以直接使用API ThreadLocalRandom,在 JDK7之前,可以做到每個線程一個實例。

  1. HashMap在容量不夠進行resize時由於高並發可能出現死鏈,導致CPU飆升,在開發過程中注意規避此風險;

10. ThreadLocal無法解決共享對象的更新問題,ThreadLocal對象建議使用static修飾。這個變量是針對一個線程內所有操作共有的,所以設置為靜態變量,所有此類實例共享此靜態變量 ,也就是說在類第一次被使用時裝載,只分配一塊存儲空間,所有此類的對象(只要是這個線程內定義的)都可以操控這個變量;

11. 單例模式推薦使用靜態內部類方式實現, 參考com.hetai.common.util. PropertiesUtils;

二  異常規范

2.1 異常規范

 

  1. 不要捕獲Java類庫中定義的繼承自RuntimeException的運行時異常類,如:IndexOutOfBoundsException / NullPointerException,這類異常由程序員預檢查來規避,保證程序健壯性。

正例:if(obj != null) {...}

反例:try { obj.method() } catch(NullPointerException e){...};

  1. 異常不要用來做流程控制,條件控制,因為異常的處理效率比條件分支低;
  2. 捕獲異常是為了處理它,不要捕獲了卻什么都不處理而拋棄之,如果不想處理它,請將該異常拋給它的調用者。最外層的業務使用者,必須處理異常,將其轉化為用戶可以理解的內容;
  3. 有try塊放到了事務代碼中,catch異常后,如果需要回滾事務,一定要注意手動回滾事務;
  4. finally塊必須對資源對象、流對象進行關閉,有異常也要做try-catch;
  5. 不能在finally塊中使用return,finally塊中的return返回后方法結束執行,不會再執行try塊中的return語句;
  6. 方法的返回值可以為null,不強制返回空集合,或者空對象等,必須添加注釋充分說明什么情況下會返回null值。調用方需要進行null判斷防止NPE問題。

說明:本規約明確防止NPE是調用者的責任。即使被調用方法返回空集合或者空對象,對調用者來說,也並非高枕無憂,必須考慮到遠程調用失敗,運行時異常等場景返回null的情況;

  1. 在接口設計中使用“返回錯誤碼”,不要直接拋異常給到調用方;
  2. 定義時區分unchecked / checked 異常,避免直接使用RuntimeException拋出,更不允許拋出Exception或者Throwable,應使用有業務含義的自定義異常。推薦業界已定義過的自定義異常,如:DAOException / ServiceException等;

10. 避免出現重復的代碼(Don’t Repeat Yourself),即DRY原則。 說明:隨意復制和粘貼代碼,必然會導致代碼的重復,在以后需要修改時,需要修改所有的副本,容易遺漏。必要時抽取共性方法,或者抽象公共類,甚至是共用模塊;

 

三  日志規范

3.1日志規范

 

  1. 應用中不要直接使用日志系統(Log4j、Logback)中的API,而應使用common包LogUtils中的API;
  2. 避免重復打印日志,浪費磁盤空間,在log4j.xml中設置additivity=false。

正例:<logger name="com.taobao.dubbo.config" additivity="false">;

  1. 異常信息應該包括兩類信息:案發現場信息和異常堆棧信息。如果不處理,則往上拋。

正例:log.error(各類參數或者對象toString + "_" + e.getMessage(), e);

  1. 注意日志輸出的級別,error級別只記錄系統邏輯出錯、異常等重要的錯誤信息。如非必要,請不要在此場景打出error級別;
  2. 日志級別按debug/info/warn/error四個級別輸出,生產環境禁止輸出debug日志;有選擇地輸出info日志;warn級別記錄系統邏輯出錯、異常等重要的錯誤信息;error級別只記錄致命的、導致流程中止的錯誤或異常信息;
  3. debug/info級別的日志輸出,必須使用使用占位符的方式,不建議使用條件輸出形式。

說明:logger.debug("Processing trade with id: " + id + " symbol: " + symbol); 如果日志級別是warn,上述日志不會打印,但是會執行字符串拼接操作,如果symbol是對象,會執行toString()方法,浪費了系統資源,執行了上述操作,最終日志卻沒有打印;

 

四 工程規范

4.1工程規范

 

  1. 包名com.hetai.系統名,代碼目錄結構按以下表格:

模塊

說明

resource

服務資源接口層,REST Resource,定義服務對外的REST 接口

service 

服務業務層,在service組裝業務邏輯 

sao     

服務遠程方法調用層,封裝調用其他服務接口 

dao     

服務持久化層,調用DB接口 

vo      

服務bean對象 

common  

服務公共代碼,如工具類、常量類等 

mapping 

調用DB sql配置文件 

extension

過濾器、攔截器filter/Interceptor 

handler 

線程處理實現類,參考《線程池使用指引》 

 

  1. 配置文件目錄結構按以下表格:

模塊

說明

dev

開發環境配置文件

commit 

測試環境(api)配置文件

commit_stg2

測試環境(api_stg2)配置文件

commit_app

測試環境(app)配置文件

formal      

正式環境配置文件

formal_app  

正式環境(app)配置文件

common

服務公共配置文件

 

 

五  安全規范

5.1 安全規范

 

  1. 隸屬於用戶個人的頁面或者功能必須進行權限控制校驗。 說明:防止沒有做水平權限校驗就可隨意訪問、操作別人的數據,比如查看、修改別人的訂單;
  2. 用戶敏感數據禁止直接展示,必須對展示數據脫敏。 說明:查看個人手機號碼會顯示成:137****5695,隱藏中間4位,防止隱私泄露;
  3. 用戶輸入的SQL參數嚴格使用參數綁定或者METADATA字段值限定,防止SQL注入,禁止字符串拼接SQL訪問數據庫;
  4. 禁止向HTML頁面輸出未經安全過濾或未正確轉義的用戶數據;
  5. 在使用平台資源,譬如短信、郵件、電話、下單、支付,必須實現正確的防重放限制,如數量限制、疲勞度控制、驗證碼校驗,避免被濫刷、資損。 說明:如注冊時發送驗證碼到手機,如果沒有限制次數和頻率,那么可以利用此功能騷擾到其它用戶,並造成短信平台資源浪費;
  6. 發貼、評論、發送即時消息等用戶生成內容的場景必須實現防刷、文本內容違禁詞過濾等風控策略;
  7. ;
  8. 表單、AJAX提交必須執行CSRF安全過濾。

說明:CSRF(Cross-site request forgery)跨站請求偽造是一類常見編程漏洞。對於存在CSRF漏洞的應用/網站,攻擊者可以事先構造好URL,只要受害者用戶一訪問,后台便在用戶不知情情況下對數據庫中用戶參數進行相應修改;

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM