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