Java后端開發規范 一、技術棧規約 二、命名規范 三、Java代碼規范(注釋規范、異常與日志、代碼邏輯規范) 四、Mybatis與SQL規范 五、結果檢查(單元測試及代碼掃描) 六、安全規范 一、技術棧規約二、命名規范- 命名使用英文詞組合,嚴禁使用中文拼音或拼音首字母組合命名(專有名詞例外) - OrganizationTreeNode, OrganizationVO ; 不推薦使用PSTree , Tlogs
- groupId,package包名前綴統一為: com.wiwj
- 包名第三位為產品分類名,如com.wiwj.cbs
- 常量命名全大寫,單詞間下劃線分隔。如: DEFAULT_PAGE_SIZE
- 其他命名遵循駝峰式命名法:類名:首字母大寫的UpperCamelCase,如: Organization方法名、變量名:首字母小寫的lowerCamelCase,如: orgName
- 特定標識命名:領域模型增加類型后綴標識,如xxVO, yyDAO基類/抽象類使用Base/Abstract等前綴標識設計模式類添加Factory,Builder,Proxy等標識Controller, Service, Mapper統一添加到對應分層目錄接口實現類添加Impl后綴標識枚舉類添加Enum后綴標識CRUD接口采用統一前綴: get, count, create, delete, update, batchCreate …
三、Java代碼規范 注釋規范- Java文件統一添加固定Header,通過IDE統一配置(code templates)
/*** <Description> <br>* @author mazhicheng@5i5j.com<br>* @version 1.0<br>* @date ${YEAR}/${MONTH}/${DAY} <br> */
/***緩存key-value并設定過期時間* @param key 緩存對象的key* @param valueList 緩存對象* @return 緩存是否成功*/<T> boolean addList(String key, List<T> valueList);
- 需暫留的棄用類/方法添加 @Deprecated 廢棄標記 和 @see 鏈接指向新接口
* @see com.wiwj.common.cache.redis.JedisSentinelPoolUtil*/@Deprecatedpublic class JedisUtils {…}
異常與日志- 調用外部服務等可能異常的代碼塊,用 try/catch 代碼塊捕獲并在catch中記錄異常跟蹤日志及業務邏輯處理
- 禁止吞掉異常信息
禁止catch里不做任何記錄和處理,吞掉異常及其堆棧信息 禁止: logger.error(“XXX操作異常”) 或 logger.error(“XXX操作異?!?e) 或 e.printStackTrace() 正確: logger.error('XXX操作異常', e) - 對于非預期的條件,盡量增加else記錄跟蹤日志
- 禁止通過System.*.out()打印日志(單元測試例外)
- 日志記錄logger需使用Slf4J代理聲明,禁止綁死具體日志系統的API,避免后期更換日志組件導致代碼的大量改動
private static final Logger log = LoggerFactory.getLogger( OrganizationServiceImpl.class); 如采用了lombok,可用 @Slf4j 注解替代以上聲明。 - 對 trace/debug/info 級別的日志輸出,必須使用占位符形式,避免直接String拼接異常信息(即使日志級別不匹配也會執行拼接操作空耗資源)。
正確寫法如: log.debug('當前用戶id: {} ,操作對象: {}=>{} ', userId, objectType, objectId);或條件輸出形式如:if(log.isDebugEnabled()){log.debug('當前用戶id: “+id+” ,操作對象: “+ objectType +”=> “+ objectId);}
邏輯代碼規范- 廢棄的/無用的代碼一律直接刪除,禁止以注釋等方式保留。如需查看歷史代碼,通過SVN/Git的history找回
(無用的代碼會干擾團隊成員的閱讀/或被誤調,越積越多會導致代碼維護成本增高) - 接口類中的方法不需添加 public 修飾符
- 需要序列化的Bean類統一實現Serializable接口并用IDE生成serialVersionUID
public class MyEntity implements Serializable { private static final long serialVersionUID = 123456L; ...}
- 常用字符串統一定義在常量類里,如: “utf-8”, “yyyyMMdd”
- 避免數字類型比較的坑: 統一采用equals進行比較其值,不用==進行比較,避免踩坑。
- if/else/for/while語句后必須使用大括號,即使只有一行代碼。(需求總是變化的,一行是暫時的)
- 嵌套層次過多的代碼塊利用反向思維縮減層次
- 方法單一職責: 單個方法代碼行數控制在100行以內,超長的需要拆分(拆分成多個方法或類)
- 避免NPE(NullPointException)的一些建議:
- equals比較將非空對象前置:如 'true'.equals(request.getParameter('isXx')),即使后者為空也不會導致NPE。
- 數據庫字段可空的映射屬性使用包裝類型定義:如基本數據類型的int映射到數據庫的null值將產生NPE,而用吧包裝類型 Integer 則不會。
- 可能為空的變量進行必要判空,并在非預期條件下打印必要的跟蹤日志,不但避免NPE,還非常便于跟蹤調試。如:
- 級聯調用 obj.getA().getB().getC() 易產生 NPE,先進行判空或使用 JDK8 的 Optional 類包裝。
- 調用Dubbo接口拿到返回值時,進行判空。
- 封裝統一的判空類用于常用類型的判空,代碼需要判空時統一調用即可。如 XX.isEmpty(), XX.isNotEmpty()
- 遵循: Don’t Repeat Yourself,即 DRY 原則。避免進行簡單的復制粘貼修改,當出現重復代碼時思考是否封裝
當代碼中存在大量重復代碼時,一旦代碼邏輯變動將很容易導致顧此失彼,產生bug,非常不利于維護。 - Bean屬性拷貝推薦用Spring BeanCopier或者Mapstruct,避免Apache BeanUtils或調用setter
- 禁止在循環中執行耗時的操作,如在循環中執行SQL語句/調用外部服務等
// 錯誤的示例:for(Long id : idList){ // 循環執行SQL查詢或調用外部系統接口,產生性能問題 Entity entity = xxService.getEntityById(id); ...} // 此案例的更優方案是 通過idList一次性查詢獲取到Entity集合,然后轉換為Map<Id, Entity>供后續獲取。
- 需要多次使用的可復用對象將對象單獨定義,禁止多次調用取不同屬性。如:
String name = userService.getUser(id).getName();Long deptId = userService.getUser(id).getDepeId();替換為:User user = userService.getUser(id); String name = user.getName(), ….
- 可異步執行的耗時操作采用異步處理:使用Spring @Async 或 MQ,或夜間Timer定時
- 常用數據考慮緩存,存入Redis,設置緩存過期時間
- 需要保證寫一致性的邏輯,在外層方法上添加事務 @Transactional(rollbackFor = Exception.class)
四、Mybatis與SQL規范- 表名、字段名、索引等數據結構定義大小寫: Oracle大寫, MySQL小寫。名稱使用英文+下劃線,并控制總長度,如 user_name。
- 表名建議采用“模塊標識_”前綴,如 bas_user(如果模塊庫獨立可省略模塊名標識)
- 禁止程序中的SQL使用并行計算 /*+parallel(t,n)*/
- SQL使用標準SQL,避免出現數據庫特定的語法
- 未經評審不可直接使用視圖、觸發器、存儲過程 SQL JOIN表數量不超過3張,超過3張表需要經過評審 (拆分成多次單表查詢、主表冗余、程序綁定id-name映射、根據條件動態JOIN等)。
- 合理創建索引,并盡量避免不走索引的情況: 如LIKE右/任意匹配('%xx’, '%xx%’)不走索引, 換為“精確匹配=”或固定前綴的左匹配’張%’不等條件(!=、<>、NOT)不走索引,應盡量避免(轉換成IN/BETWEEN等)IS (NOT) NULL 不走索引,應盡量避免(如字段給定默認值,避免NULL)索引列使用函數或隱式轉換都將導致索引失效,如 to_char(create_date,'yyyymmdd') = '20190102'
- 禁止手動拼接SQL語句,利用Mybatis等ORM框架的動態SQL實現。 參數使用#{} (避免${}產生SQL注入問題)。
- 禁止使用數據庫處理函數 decode(),改為Java枚舉或Map定義,通過id進行綁定 decode(client.TYPE, 1, '私客', 2, '店組公客', 3, '組團公客')
- 禁止動態拼接時強加 1=1 之類的寫法,如WHERE 1=1。使用Mybatis動態SQL標簽實現,如<where>,<set>,<trim>
- SQL中的參數類型確保與列定義一致,避免數據庫隱式轉換開銷且無法使用索引,如:列定義為日期類型,參數要轉換為Date日期類型進行比較:
CREATE_TIME <= '2019-04-14 23:59:59’CREATE_TIME <= to_date('2019-04-14 00:00:00','yyyy-MM-dd HH24:mi:ss’)
- 列定義為數字類型,參數不用String DEPT_ID = '123’
- ID主鍵自增的情況下,按create_time排序改為按ID排序,效果一樣效率更高
五、檢查結果- 后端服務及其他需要自測的代碼,編寫對應的單元測試類,統一采用Junit,禁止直接在原Java類中寫main()方法自測。
單元測試會在打包前統一運行,可及時發現受影響的代碼問題(比如新代碼導致了之前的代碼邏輯產生問題,如果有單元測試可在打包時及時發現)Junit單元測試類示例:public class TestApollo {@Test // 標記為單元測試方法public void testApolloConfig(){String appId = Foundation.app().getAppId();// 預期結果斷言Assert.assertNotNull(appId);}}
- IDE中安裝代碼質量檢查插件: FindBugs 及 Alibaba Java Coding Guidelines
六、安全規約說明:本文限于篇幅,故而只展示部分的面試內容,完整的Java面試學習文檔小編已經幫你整理好了,有需要的朋友點贊+關注私信我777免費領取Java、大廠面試學習資料哦!
|