JAVA基礎--JAVA代碼規範

簡介

1.1. 目的

本文檔將從提高代碼的一致性,可讀性以及可維護性。並通過配置文件等手段,提高代碼的可擴展性爲出發點,制定相應的軟件開發流程,目標是培養工程師面向對象編程的思維;同時保證項目在提交測試組之前,開發人員已針對所有的功能模塊通過了開發級別的單元測試.

關於代碼規範我總結幾個原則:

  1. 命名要做到--見名知義。 要讓別人一看這個方法、變量就能大概知道什麼作用。

  2. 對接外部請求、數據庫請求、rest請求,做到:請求數量最小化原則。比如:儘量不要在for循環中發請求、請求數據一次能請求多個數據,就不要一個個發。

  3. 對外部請求,最好增加兩個:logger.info(params); logger.info(resultData); 方便日後問題 排查。

  4. 對就異常:新項目已經做到了,對所有的異常進行 攔截處理,把返回一個通用的ResultTo對象。異常的捕捉和拋出是有講究的:

    ​ a:條件必須滿足,不滿足就可以拋出,或者方法中止:返回ResultTo

    b:這個條件不是必須的,不滿足也要保證程序斷續運行的,可以使用:try…catch.

  5. 如果程序接口,已經遵循:rest風格標準,大家在使用的時候:可以使用對應的請求。比如:

    @PostMapping post請求

    @GetMapping 查詢操作

    @PutMapping :更新操作

    @DeleteMapping :刪除操作。

編碼規範

2.1. 開發環境

通過Maven建立項目(Java項目和動態Web項目),並通過pom.xml管理項目版本;通過pom.xml中的dependencies統一管理第三方API。

  • 開發工具統一採用64位的Eclipse、STS、IDEA。
  • 代碼通過SVN統一管理。
  • JDK統一採用jdk-7 - 64位版本。
  • TOMCAT使用:tomcat7.

2.2. 代碼格式規範

註釋

所有的接口、類、Enumeration和方法(get和set方法除外)都應有註釋。註釋參照javadoc的註釋方式 (除@author和@version,其他的*@標識暫不做硬性規定):

 //1:註解釋
/**
 * <p>
 *  這是一個類註釋,或者代碼塊註釋
 * </p>
 * @author wangsan
 * @date 2018年xx月xx日下午1:26:26
 */
//2:行註釋
//方法體內,行註釋
/** 成員變量,註釋 */

2.3. 包名解釋

1: com.ch.項目名稱: 如:com.xx.xx 2: 項目按功能劃分, 如果是同一個人做的功能,相同的功能儘量放在一個包裏,避免過多的類。

  • Contoller:控制層:註解:@Controller
  • Service:業務層:註解:@Service 或者 @Component(不建議),自動註解的beanName爲類名字母小寫。
  • Entity:實體層。此層的定義上,沒有規範,原則上此層上必須一個基類,如FM: BaseEntity 、BasicDb,使用一個即可。這樣方便進行統一管理:如序列化,AOP操作等。
  • Dao: 數據庫持久層。註解:@Repository
  • mapper:mybatis實現層。

2.4. 異常處理

Java 異常(Exception)處理三原則:

  • 一定不能處理的異常,就不要捕捉
  • 如果捕捉了異常,就一定要處理
  • 儘量捕捉自己定義的異常

每個項目的util包中將定義一個Constants類。其中包含所有系統中要用到的常量,且必須使用static和final修飾符。 只在一個類中使用的常量定義到該類的首部,使用final修飾符。

3. 開發過程的規範

3.1. 單元測試

  1. 開發工程師必須針對每個業務邏輯功能方法進行單元測試(使用junit)。必須所有junit測試用例通過的功能纔可以提交進入業務邏輯階段測試。
  2. 測試包:src/test/java
  3. 在單元測試包,必須放在需要測試的類同包名。類名:爲測試類名+Test
  4. 測試一般可對:service 或 controller層進行。
  5. 測試工程師:集成測試 (這部分內容需要測試部門決定規範)
  6. 業務人員:系統測試 (這部分內容需要產品部門以及QA決定規範)

3.2. 常量層訪問CONSTANTS

避免通過一個類的對象引用訪問此類的靜態變量或靜態方法,會增加編譯器解析成 本,直接用類名來訪問即可

3.3. 工具類的使用

通用功能放在要封裝一個工具類,如果沒有對應的方法,可適量增加。 方便統一維護、和後期JAR升級和替換。

儘量不要在自己的業務,使用比較複雜的方法:一是導致業務代碼量過多,二是不便於升級維護。 三是:不能通用,造成代碼冗餘。 StrUtil 字符串操作類 : JsonUtil JSON操作類 DateUtil 日期操作類 FileUtils 文件流操作類。

3.4. 影響性能方面的注意

  • 在循環體中,字符串拼接必須使用StringBuffer,或者StringBuilder
  • 在循環體中,不能頻繁讀取數據庫數據
  • 異常注意捕獲,並記錄日誌(方便發生異常時排查錯誤)
  • 注意文件和方法命名規範;(駝峯命名法、帕斯卡命名法)類和方法名簡潔而富於描述。避免使用關鍵字
  • 文件、數據庫等打開後,在對其進行操作之後是否進行了關閉,包括異常情況下關閉
  • 方法的參數與返回類型變化時必須加上修改原因。

3.5. 日誌記錄

  • 輸出場景:登錄操作、數據變更、文件變化、接口服務、支付應答(對外回調函數)、
  • 輸出內容:誰(userid,ip)什麼時間幹了什麼事情(執行SQL),並對用戶信息等敏感數據加密
  • 重要方法(如籤派放行、動態圖)需要加上方法的執行時間

3.6. 安全

  • 輸入參數雙層校驗:除前端校驗外,服務端也需要校驗。
  • 校驗數據長度、格式、類型是否符合要求(如參數加密,解密後也要校驗)
  • 頁面需要有權限控制,不要出現登錄後,手工輸入某url就能訪問該頁面
  • 密碼強度必須達到中等以上強度(8位以上,大小寫英文字母+數字組合),且半年內不修改密碼需要做密碼修改提醒

3.7. 接口規範

  • 輸入參數必須做非空校驗與有效性校驗,校驗不通過的,有清晰的錯誤提示給調用方
  • 對內接口設置白名單,對外接口用戶密碼驗證
  • 接口返回數據量必須控制(如單次調用控制在500條數據量內)
  • 接口入口和出口,必須輸出Log,並對用戶信息,單據等敏感數據加密
  • 接口參數變更,原接口保留,新建一個相似命名接口。所有接口變更,必須郵件通知所有項目經理,並要求答覆

3.8. 數據庫

  • 命名規範,命名只能英文字母,數字和下劃線。避免關鍵字
  • 數據庫表設計考慮主鍵、索引
  • 所有字段必須註釋,存儲過程註釋同java,涉及複雜算法,邏輯判斷必須有註釋,儘量不要使用,存儲過程,不便於維護。
  • ibatis用queryForObject時需確保不可能查出多條記錄
  • sql語句中,表內字段儘可能避免套函數,以免不走索引或者需要重新添加函數索引
  • ibtatis參數或返回類型變化必須加修改原因。
  • 刪除和更新語句需要加條件,避免沒傳參數值而對整表的數據做更改操作。
  • 索引字段前不能加函數。

3.9. 頁面

  • 按鈕要做重複點擊的控制
  • 日期範圍查詢的要做範圍控制,特別是當數據量可能很大的時候
  • 頁面資源不能重複加載,如js、css等,相同的可以考慮使用緩存。
  • 頁面加載時間超過3秒考慮用異步加載或進度條的方式。

3.10.創建類的實例用clone

不用new關鍵詞創建類的實例可使用clone代替 用 new 關鍵詞創建類的實例時,構造函數鏈中的所有構造函數都會被自動調用。但如 果一個對象實現了 Cloneable 接口,我們可以調用它的 clone()方法。clone()方法不會調用任 何類構造函數。 在使用設計模式(Design Pattern)的場合,如果用 Factory 模式創建對象,則改用 clone() 方法創建新的對象實例非常簡單。例如,下面是 Factory 模式的一個典型實現:

    public static Credit getNewCredit() {
        return new Credit();
    }

    //改進後的代碼使用 clone()方法,如下所示:
    private static Credit BaseCredit = new Credit();
    public static Credit getNewCredit() {
        return (Credit) BaseCredit.clone();
    }

3.11.儘量使用局部變量

調用方法時傳遞的參數以及在調用中創建的臨時變量都保存在棧(Stack)中,速度較 快。其他變量,如靜態變量、實例變量等,都在堆(Heap)中創建,速度較慢。另外,依 賴於具體的編譯器/JVM,局部變量還可能得到進一步優化。

3.12.乘法和除法

比如下面的代碼:

        int alterX = 1  ,myResult = 1;
        for (int val = 0; val < 100000; val += 5) {
            alterX = val * 8;
            myResult = val * 2;
        }
        //用移位操作替代乘法操作可以極大地提高性能
        for (int val = 0; val < 100000; val += 5) {
            alterX = val << 3;
            myResult = val << 1;
        }

修改後的代碼不再做乘以8的操作,而是改用等價的左移3位操作,每左移1位相當於乘 以2。相應地,右移1位操作相當於除以2。值得一提的是,雖然移位操作速度快,但可能使 代碼比較難於理解,所以最好加上一些註釋。

3.13.選擇合適的引用機制

在典型的 JSP 應用系統中,頁頭、頁腳部分往往被抽取出來,然後根據需要引入頁頭、 頁腳。當前,在 JSP 頁面中引入外部資源的方法主要有兩種:include 指令,以及 include 動 作。 include 指令:例如<%@ include file="copyright.html" %>。該指令在編譯時引入指定的 資源。在編譯之前,帶有 include 指令的頁面和指定的資源被合併成一個文件。被引用的外 部資源在編譯時就確定,比運行時才確定資源更高效。 include 動作:例如。該動作引入指定頁面執行後生成的結果。由於它在運行時完成,因此對輸出結果的控制更加靈活。

3.14.選擇使用JS、css引用

使用JS引用來代替在JSP頁面中:

<script src="${ctx}/static/js/../jsName.js"></script> 
<!--代替:-->
<script>
    //js code
</script> 

<link rel="stylesheet" href="${ctx}/static/css/../cssName.css"> 
<!--代替:-->
<style>
    //css code
</style>

3.15. 可能使用WEBSOCKET的場景儘量使用

如果項目中有對實時性要求較高的場景,可以考慮使用webSocket, 長鏈接方式代替頻繁請求。

3.16.頻繁的請求可以使用放入REDIS中使用。

項目中推薦使用:RedisSingleUtils.JAVA 裏面有很多方法,可以滿足你的要求。

3.17. 數據庫操作

SQL語句方面儘量做到最優寫法。比如:靈活使用索引、函數。

  1. 使用一個結果集來代碼多次取。這個可以看出,如果獲得的越多,速度會成倍的減慢、當數據量大的,這個差別是非常明顯的。
--查詢1 代替查詢2
SELECT SUM(decode(m.msg_from,'1',1,0)),SUM(decode(m.msg_from,'0',1,0))
FROM t_tableName1 m;

--查詢2
SELECT  (    
    SELECT count(m.id) 
    FROM t_tableName1 m
    WHERE m.msg_from='1'        
) aaa ,  (
    SELECT count(m.id) 
    FROM t_tableName1 m
    WHERE m.msg_from='0'
) bbb FROM dual ;
  1. 沒有必要的日期轉換,雖然ORACLE的日期轉換效率高,但是在數據量多少,也會花費一些時間。所在在大數據量時採用一和二。
--查詢1 0.016
select count(*) from t_tableName1 t where t.read_date > date'2017-08-11' and t.read_date < date'2017-08-12' ;
--查詢2 0.016
select count(*) from t_tableName1 t where t.read_date > to_date('2017-07-06 00:00:00','YYYY-MM-DD HH24:MI:SS') and t.read_date <  to_date('2017-07-06 23:59:59','YYYY-MM-DD HH24:MI:SS');

--代替 0.031
select count(*) from t_tableName1 t where to_char(t.read_date,'YYYY-MM-DD') = '2017-08-11' ; 

2:項目使用Mybatis作用數據庫的持久層。在某些情況下:會用到一些共有的SQL語句,能用共用就儘量使用。防止在代碼修改過程,漏掉一些修改,導致一些低級的錯誤發生。在使用過程中,靈活使用mybatis提供的標籤,如:

<if test="endDate !=null and endDate !='' and planSts == '5'.toString()">
  and to_char(t.END_DATA,'yyyy-mm-dd') &lt;=#{endDate}
</if>

<foreach collection="" separator="" close="" index="" item="" open=""></foreach>

<choose>
         <when test=""></when>
         <otherwise></otherwise>
</choose>
<select id="selectMapList" resultMap="mapResultMap" parameterType="map" >
    select
    <include refid="entityColumn" />
    from ACARS_RAWMSG_ERROR_LOG
    <include refid="whereCondition" />
</select>

<sql id="entityColumn" >
    aaa,bbb,ccc,ddd,STATUS,CREATE_TIME
</sql>

<sql id="whereCondition" >
    <where >
      <if test="dbName != null and dbName != '' " >
         and DB_NAME = #{dbName,jdbcType=VARCHAR}
      </if>
    </where>
</sql> 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章