# 阿里巴巴Java开呿‰‹å†Œç»ˆçº§ç‰ˆï¼ˆ1.3.0) ## å‰è¨€ 《阿里巴巴Java开呿‰‹å†Œã€‹æ˜¯é˜¿é‡Œå·´å·´é›†å›¢æŠ€æœ¯å›¢é˜Ÿçš„集体智慧结晶和ç»éªŒæ€» 结,ç»åŽ†äº†å¤šæ¬¡å¤§è§„æ¨¡ä¸€çº¿å®žæˆ˜çš„æ£€éªŒåŠä¸æ–çš„å®Œå–„ï¼Œç³»ç»ŸåŒ–åœ°æ•´ç†æˆå†Œï¼Œå馈给广 大开å‘者。现代软件行业的高速å‘展对开å‘者的综åˆç´ è´¨è¦æ±‚è¶Šæ¥è¶Šé«˜ï¼Œå› 为ä¸ä»…是 编程知识点,其它维度的知识点也会影å“到软件的最终交付质é‡ã€‚比如:数æ®åº“的表 结构和索引设计缺陷å¯èƒ½å¸¦æ¥è½¯ä»¶ä¸Šçš„æž¶æž„缺陷或性能风险;工程结构混乱导致åŽç» 维护艰难;没有鉴æƒçš„æ¼æ´žä»£ç æ˜“被黑客攻击ç‰ç‰ã€‚所以本手册以 Java å¼€å‘者为ä¸å¿ƒ 视角,划分为编程规约ã€å¼‚常日志ã€å•元测试ã€å®‰å…¨è§„约ã€å·¥ç¨‹ç»“æž„ã€MySQL æ•°æ®åº“å… ä¸ªç»´åº¦ï¼Œå†æ ¹æ®å†…容特å¾ï¼Œç»†åˆ†æˆè‹¥å¹²äºŒçº§åç›®å½•ã€‚æ ¹æ®çº¦æŸåŠ›å¼ºå¼±åŠæ•…éšœæ•æ„Ÿæ€§ï¼Œ è§„çº¦ä¾æ¬¡åˆ†ä¸ºå¼ºåˆ¶ã€æŽ¨èã€å‚考三大类。对于规约æ¡ç›®çš„延伸信æ¯ä¸ï¼Œâ€œè¯´æ˜Žâ€å¯¹å†… 容åšäº†é€‚当扩展和解释;“æ£ä¾‹â€æå€¡ä»€ä¹ˆæ ·çš„ç¼–ç 和实现方å¼ï¼› “å例â€è¯´æ˜Žéœ€è¦ æé˜²çš„雷区,以åŠçœŸå®žçš„错误案例。 本手册的愿景是ç 出高效,ç 出质é‡ã€‚现代软件架构都需è¦ååŒå¼€å‘完æˆï¼Œé«˜æ•ˆ å作å³é™ä½ŽååŒæˆæœ¬ï¼Œæå‡æ²Ÿé€šæ•ˆçŽ‡ï¼Œæ‰€è°“æ— è§„çŸ©ä¸æˆæ–¹åœ†ï¼Œæ— 规范ä¸èƒ½å作。众所 周知,制订交通法规表é¢ä¸Šæ˜¯è¦é™åˆ¶è¡Œè½¦æƒï¼Œå®žé™…上是ä¿éšœå…¬ä¼—的人身安全。试想如 果没有é™é€Ÿï¼Œæ²¡æœ‰çº¢ç»¿ç¯ï¼Œè°è¿˜æ•¢ä¸Šè·¯è¡Œé©¶ã€‚对软件æ¥è¯´ï¼Œé€‚å½“çš„è§„èŒƒå’Œæ ‡å‡†ç»ä¸æ˜¯ 消ç代ç å†…å®¹çš„åˆ›é€ æ€§ã€ä¼˜é›…性,而是é™åˆ¶è¿‡åº¦ä¸ªæ€§åŒ–ï¼Œä»¥ä¸€ç§æ™®é认å¯çš„ç»Ÿä¸€æ–¹å¼ ä¸€èµ·åšäº‹ï¼Œæå‡å作效率。代ç çš„å—é‡Œè¡Œé—´æµæ·Œçš„æ˜¯è½¯ä»¶ç”Ÿå‘½ä¸çš„血液,质é‡çš„æå‡ 是尽å¯èƒ½å°‘踩å‘,æœç»è¸©é‡å¤çš„å‘,切实æå‡è´¨é‡æ„识。 考虑到å¯ä»¥é›¶è·ç¦»åœ°ä¸Žä¼—多开å‘åŒå¦è¿›è¡Œäº’åŠ¨ï¼Œå†³å®šåœ¨çº¿ç»´æŠ¤ã€Šæ‰‹å†Œã€‹å†…å®¹ï¼Œæ¤ ç‰ˆæœ¬å·ä¸º 1.3.0 çš„ PDF 版本,是对外释放的终æžç‰ˆï¼›å…¶æ¬¡ï¼Œæˆ‘们会在 2017 å¹´ 10 月 14 æ—¥æå·žäº‘æ –å¤§ä¼šä¸Šï¼Œè¿›è¡Œé˜¿é‡Œå·´å·´ Java å¼€å‘规约æ’ä»¶å…¨çƒé¦–å‘,æ’件点æ¤ä¸‹è½½ï¼Œé˜¿é‡Œ 巴巴云效(一站å¼ä¼ä¸šååŒç ”å‘云)也会集æˆä»£ç 规约扫æå¼•擎。最åŽï¼Œã€Šç 出高效 ——详解》å³å°†å‡ºç‰ˆï¼Œæ•¬è¯·å…³æ³¨ã€‚ ## 目录 å‰è¨€ 一ã€ç¼–程规约 ......................................................................... 1 (一) 命åé£Žæ ¼ ...................................................................1 (二) 常é‡å®šä¹‰ ...................................................................3 (三) ä»£ç æ ¼å¼ ..................................................................4 (å››) OOP 规约...................................................................6 (五) 集åˆå¤„ç† ...................................................................9 (å…) å¹¶å‘å¤„ç† ..................................................................12 (七) 控制è¯å¥ ..................................................................14 (å…«) 注释规约 ..................................................................16 (ä¹) 其它 ......................................................................17 二ã€å¼‚常日志 ........................................................................ 18 (一) å¼‚å¸¸å¤„ç† .................................................................. 18 (二) 日志规约 .................................................................. 19 三ã€å•元测试 ........................................................................ 21 å››ã€å®‰å…¨è§„约 ........................................................................ 23 五ã€MySQL æ•°æ®åº“ .................................................................... 24 (一) 建表规约 ..................................................................24 (二) 索引规约 ..................................................................25 (三) SQL è¯å¥..................................................................27 (å››) ORM æ˜ å°„..................................................................28 å…ã€å·¥ç¨‹ç»“æž„ ........................................................................ 30 (一) 应用分层 ..................................................................30 (二) 二方库ä¾èµ– ................................................................31 (三) æœåС噍 .................................................................... 32 附 1ï¼šç‰ˆæœ¬åŽ†å² ....................................................................... 34 附 2:本手册专有åè¯ ................................................................. 35 (注:æµè§ˆæ—¶è¯·ä½¿ç”¨ PDF 左侧导航æ ) # Java 开呿‰‹å†Œ | ç‰ˆæœ¬å· | 制定团队 | 更新日期 | 备注 | | 1.3.0 | 阿里巴巴集团技术团队 | 2017.9.25 å¢žåŠ å•元测试规约(PDF 终æžç‰ˆï¼‰| # 一ã€ç¼–程规约 ## (一)命åé£Žæ ¼ ### 1. ã€å¼ºåˆ¶ã€‘代ç ä¸çš„命åå‡ä¸èƒ½ä»¥ä¸‹åˆ’线或美元符å·å¼€å§‹ï¼Œä¹Ÿä¸èƒ½ä»¥ä¸‹åˆ’线或美元符å·ç»“æŸã€‚ å例:_name / __name / $Object / name_ / name$ / Object$ ### 2. ã€å¼ºåˆ¶ã€‘代ç ä¸çš„命å严ç¦ä½¿ç”¨æ‹¼éŸ³ä¸Žè‹±æ–‡æ··åˆçš„æ–¹å¼ï¼Œæ›´ä¸å…è®¸ç›´æŽ¥ä½¿ç”¨ä¸æ–‡çš„æ–¹å¼ã€‚ 说明:æ£ç¡®çš„è‹±æ–‡æ‹¼å†™å’Œè¯æ³•å¯ä»¥è®©é˜…读者易于ç†è§£ï¼Œé¿å…æ§ä¹‰ã€‚注æ„,å³ä½¿çº¯æ‹¼éŸ³å‘½åæ–¹å¼ ä¹Ÿè¦é¿å…采用。 æ£ä¾‹ï¼šalibaba / taobao / youku / hangzhou ç‰å›½é™…通用的å称,å¯è§†åŒè‹±æ–‡ã€‚ å例:DaZhePromotion [打折] / getPingfenByName() [评分] / int æŸå˜é‡ = 3 ### 3. ã€å¼ºåˆ¶ã€‘ç±»å使用 UpperCamelCase é£Žæ ¼ï¼Œå¿…é¡»éµä»Žé©¼å³°å½¢å¼ï¼Œä½†ä»¥ä¸‹æƒ…形例外:DO / BO / DTO / VO / AO æ£ä¾‹ï¼šMarcoPolo / UserDO / XmlService / TcpUdpDeal / TaPromotion å例:macroPolo / UserDo / XMLService / TCPUDPDeal / TAPromotion ### 4. ã€å¼ºåˆ¶ã€‘方法åã€å‚æ•°åã€æˆå‘˜å˜é‡ã€å±€éƒ¨å˜é‡éƒ½ç»Ÿä¸€ä½¿ç”¨ lowerCamelCase é£Žæ ¼ï¼Œå¿…é¡»éµä»Ž 驼峰形å¼ã€‚ æ£ä¾‹ï¼š localValue / getHttpMessage() / inputUserId ### 5. ã€å¼ºåˆ¶ã€‘常é‡å‘½å全部大写,å•è¯é—´ç”¨ä¸‹åˆ’线隔开,力求è¯ä¹‰è¡¨è¾¾å®Œæ•´æ¸…楚,ä¸è¦å«Œåå—长。 æ£ä¾‹ï¼šMAX_STOCK_COUNT å例:MAX_COUNT ### 6. ã€å¼ºåˆ¶ã€‘抽象类命å使用 Abstract 或 Base 开头;异常类命å使用 Exception 结尾;测试类 命åä»¥å®ƒè¦æµ‹è¯•的类的å称开始,以 Test 结尾。 ### 7. ã€å¼ºåˆ¶ã€‘䏿‹¬å·æ˜¯æ•°ç»„类型的一部分,数组定义如下:String[] args; å例:使用 String args[]çš„æ–¹å¼æ¥å®šä¹‰ã€‚ ### 8. ã€å¼ºåˆ¶ã€‘POJO ç±»ä¸å¸ƒå°”类型的å˜é‡ï¼Œéƒ½ä¸è¦åŠ is,å¦åˆ™éƒ¨åˆ†æ¡†æž¶è§£æžä¼šå¼•èµ·åºåˆ—化错误。 å例:定义为基本数æ®ç±»åž‹ Boolean isDeleted;的属性,它的方法也是 isDeleted(),RPC 框架在åå‘è§£æžçš„æ—¶å€™ï¼Œâ€œä»¥ä¸ºâ€å¯¹åº”的属性å称是 deleted,导致属性获å–ä¸åˆ°ï¼Œè¿›è€ŒæŠ›å‡ºå¼‚ 常。 ### 9. ã€å¼ºåˆ¶ã€‘包å统一使用å°å†™ï¼Œç‚¹åˆ†éš”符之间有且仅有一个自然è¯ä¹‰çš„英è¯å•è¯ã€‚包å统一使用 啿•°å½¢å¼ï¼Œä½†æ˜¯ç±»åå¦‚æžœæœ‰å¤æ•°å«ä¹‰ï¼Œç±»åå¯ä»¥ä½¿ç”¨å¤æ•°å½¢å¼ã€‚ æ£ä¾‹ï¼š 应用工具类包å为 com.alibaba.open.utilã€ç±»å为 MessageUtils(æ¤è§„则å‚考 spring 的框架结构) ### 10. ã€å¼ºåˆ¶ã€‘æœç»å®Œå…¨ä¸è§„范的缩写,é¿å…望文ä¸çŸ¥ä¹‰ã€‚ å例:AbstractClass“缩写â€å‘½åæˆ AbsClassï¼›condition“缩写â€å‘½åæˆ condi,æ¤ç±»éš æ„ç¼©å†™ä¸¥é‡é™ä½Žäº†ä»£ç çš„å¯é˜…读性。 ### 11. ã€æŽ¨è】为了达到代ç è‡ªè§£é‡Šçš„ç›®æ ‡ï¼Œä»»ä½•è‡ªå®šä¹‰ç¼–ç¨‹å…ƒç´ åœ¨å‘½åæ—¶ï¼Œä½¿ç”¨å°½é‡å®Œæ•´çš„å•è¯ ç»„åˆæ¥è¡¨è¾¾å…¶æ„。 æ£ä¾‹ï¼šä»Žè¿œç¨‹ä»“库拉å–代ç 的类命å为 PullCodeFromRemoteRepository。 å例:å˜é‡ int a; çš„éšæ„命忖¹å¼ã€‚ ### 12. ã€æŽ¨è】如果模å—ã€æŽ¥å£ã€ç±»ã€æ–¹æ³•使用了设计模å¼ï¼Œåœ¨å‘½å时体现出具体模å¼ã€‚ 说明:将设计模å¼ä½“现在åå—ä¸ï¼Œæœ‰åˆ©äºŽé˜…读者快速ç†è§£æž¶æž„设计ç†å¿µã€‚ æ£ä¾‹ï¼špublic class OrderFactory; public class LoginProxy; public class ResourceObserver; ### 13. ã€æŽ¨è】接å£ç±»ä¸çš„æ–¹æ³•和属性ä¸è¦åŠ ä»»ä½•ä¿®é¥°ç¬¦å·ï¼ˆpublic 也ä¸è¦åŠ ï¼‰ï¼Œä¿æŒä»£ç çš„ç®€æ´ æ€§ï¼Œå¹¶åŠ ä¸Šæœ‰æ•ˆçš„ Javadoc 注释。尽é‡ä¸è¦åœ¨æŽ¥å£é‡Œå®šä¹‰å˜é‡ï¼Œå¦‚果一定è¦å®šä¹‰å˜é‡ï¼Œè‚¯å®šæ˜¯ ä¸ŽæŽ¥å£æ–¹æ³•相关,并且是整个应用的基础常é‡ã€‚ æ£ä¾‹ï¼šæŽ¥å£æ–¹æ³•ç¾å:void f(); 接å£åŸºç¡€å¸¸é‡è¡¨ç¤ºï¼šString COMPANY = "alibaba"; åä¾‹ï¼šæŽ¥å£æ–¹æ³•定义:public abstract void f(); 说明:JDK8 䏿ޥå£å…许有默认实现,那么这个 default 方法,是对所有实现类都有价值的默 认实现。 ### 14. 接å£å’Œå®žçŽ°ç±»çš„å‘½åæœ‰ä¸¤å¥—规则: 1)ã€å¼ºåˆ¶ã€‘对于 Service å’Œ DAO 类,基于 SOA çš„ç†å¿µï¼Œæš´éœ²å‡ºæ¥çš„æœåŠ¡ä¸€å®šæ˜¯æŽ¥å£ï¼Œå†…部 的实现类用 Impl çš„åŽç¼€ä¸ŽæŽ¥å£åŒºåˆ«ã€‚ æ£ä¾‹ï¼šCacheServiceImpl 实现 CacheService 接å£ã€‚ 2ï¼‰ã€æŽ¨è】如果是形容能力的接å£å称,å–对应的形容è¯åšæŽ¥å£å(通常是–able 的形å¼ï¼‰ã€‚ æ£ä¾‹ï¼šAbstractTranslator 实现 Translatable。 ### 15. ã€å‚考】枚举类å建议带上 Enum åŽç¼€ï¼Œæžšä¸¾æˆå‘˜å称需è¦å…¨å¤§å†™ï¼Œå•è¯é—´ç”¨ä¸‹åˆ’线隔开。 说明:枚举其实就是特殊的常é‡ç±»ï¼Œä¸”æž„é€ æ–¹æ³•è¢«é»˜è®¤å¼ºåˆ¶æ˜¯ç§æœ‰ã€‚ æ£ä¾‹ï¼šæžšä¸¾åå—为 ProcessStatusEnum çš„æˆå‘˜å称:SUCCESS / UNKOWN_REASON。 ### 16. ã€å‚考】å„层命å规约: #### A) Service/DAO 层方法命å规约 1) 获å–å•个对象的方法用 get åšå‰ç¼€ã€‚ 2) 获å–多个对象的方法用 list åšå‰ç¼€ã€‚ 3) 获å–统计值的方法用 count åšå‰ç¼€ã€‚ 4) æ’入的方法用 save/insert åšå‰ç¼€ã€‚ 5) åˆ é™¤çš„æ–¹æ³•ç”¨ remove/delete åšå‰ç¼€ã€‚ 6) 修改的方法用 update åšå‰ç¼€ã€‚ #### B) 领域模型命å规约 1) æ•°æ®å¯¹è±¡ï¼šxxxDO,xxx å³ä¸ºæ•°æ®è¡¨å。 2) æ•°æ®ä¼ 输对象:xxxDTO,xxx 为业务领域相关的å称。 3) 展示对象:xxxVO,xxx 一般为网页å称。 4) POJO 是 DO/DTO/BO/VO çš„ç»Ÿç§°ï¼Œç¦æ¢å‘½åæˆ xxxPOJO。 ## (二)常é‡å®šä¹‰ ### 1. ã€å¼ºåˆ¶ã€‘ä¸å…è®¸ä»»ä½•é”æ³•å€¼ï¼ˆå³æœªç»å®šä¹‰çš„常é‡ï¼‰ç›´æŽ¥å‡ºçŽ°åœ¨ä»£ç ä¸ã€‚ å例: ``` java String key = "Id#taobao_" + tradeId; cache.put(key, value); ``` ### 2. ã€å¼ºåˆ¶ã€‘long 或者 Long åˆå§‹èµ‹å€¼æ—¶ï¼Œä½¿ç”¨å¤§å†™çš„ L,ä¸èƒ½æ˜¯å°å†™çš„ l,å°å†™å®¹æ˜“è·Ÿæ•°å— 1 æ··æ·†ï¼Œé€ æˆè¯¯è§£ã€‚ 说明:Long a = 2l; 写的是数å—çš„ 21,还是 Long 型的 2? ### 3. ã€æŽ¨è】ä¸è¦ä½¿ç”¨ä¸€ä¸ªå¸¸é‡ç±»ç»´æŠ¤æ‰€æœ‰å¸¸é‡ï¼ŒæŒ‰å¸¸é‡åŠŸèƒ½è¿›è¡Œå½’ç±»ï¼Œåˆ†å¼€ç»´æŠ¤ã€‚ 说明:大而全的常é‡ç±»ï¼Œéžå¾—使用查找功能æ‰èƒ½å®šä½åˆ°ä¿®æ”¹çš„常é‡ï¼Œä¸åˆ©äºŽç†è§£å’Œç»´æŠ¤ã€‚ æ£ä¾‹ï¼šç¼“å˜ç›¸å…³å¸¸é‡æ”¾åœ¨ç±» CacheConsts 下;系统é…ç½®ç›¸å…³å¸¸é‡æ”¾åœ¨ç±» ConfigConsts 下。 ### 4. ã€æŽ¨è】常é‡çš„å¤ç”¨å±‚次有五层:跨应用共享常é‡ã€åº”用内共享常é‡ã€å工程内共享常é‡ã€åŒ… 内共享常é‡ã€ç±»å†…共享常é‡ã€‚ 1) 跨应用共享常é‡ï¼šæ”¾ç½®åœ¨äºŒæ–¹åº“ä¸ï¼Œé€šå¸¸æ˜¯ client.jar ä¸çš„ constant 目录下。 2) 应用内共享常é‡ï¼šæ”¾ç½®åœ¨ä¸€æ–¹åº“ä¸ï¼Œé€šå¸¸æ˜¯ modules ä¸çš„ constant 目录下。 å例:易懂å˜é‡ä¹Ÿè¦ç»Ÿä¸€å®šä¹‰æˆåº”用内共享常é‡ï¼Œä¸¤ä½æ”»åŸŽå¸ˆåœ¨ä¸¤ä¸ªç±»ä¸åˆ†åˆ«å®šä¹‰äº†è¡¨ç¤º “是â€çš„å˜é‡ï¼š ç±» A ä¸ï¼špublic static final String YES = "yes"; ç±» B ä¸ï¼špublic static final String YES = "y"; A.YES.equals(B.YES),预期是 true,但实际返回为 false,导致线上问题。 3) å工程内部共享常é‡ï¼šå³åœ¨å½“å‰å工程的 constant 目录下。 4) 包内共享常é‡ï¼šå³åœ¨å½“å‰åŒ…下å•独的 constant 目录下。 5) 类内共享常é‡ï¼šç›´æŽ¥åœ¨ç±»å†…部 private static final 定义。 ### 5. ã€æŽ¨è】如果å˜é‡å€¼ä»…在一个范围内å˜åŒ–,且带有åç§°ä¹‹å¤–çš„å»¶ä¼¸å±žæ€§ï¼Œå®šä¹‰ä¸ºæžšä¸¾ç±»ã€‚ä¸‹é¢ æ£ä¾‹ä¸çš„æ•°å—就是延伸信æ¯ï¼Œè¡¨ç¤ºæ˜ŸæœŸå‡ 。 æ£ä¾‹ï¼špublic Enum { MONDAY(1), TUESDAY(2), WEDNESDAY(3), THURSDAY(4), FRIDAY(5), SATURDAY(6), SUNDAY(7);} ## (三)ä»£ç æ ¼å¼ ### 1. ã€å¼ºåˆ¶ã€‘大括å·çš„使用约定。如果是大括å·å†…为空,则简æ´åœ°å†™æˆ{}å³å¯ï¼Œä¸éœ€è¦æ¢è¡Œï¼›å¦‚æžœ 是éžç©ºä»£ç å—则: 1) 左大括å·å‰ä¸æ¢è¡Œã€‚ 2) 左大括å·åŽæ¢è¡Œã€‚ 3) å³å¤§æ‹¬å·å‰æ¢è¡Œã€‚ 4) å³å¤§æ‹¬å·åŽè¿˜æœ‰ else ç‰ä»£ç åˆ™ä¸æ¢è¡Œï¼›è¡¨ç¤ºç»ˆæ¢çš„å³å¤§æ‹¬å·åŽå¿…é¡»æ¢è¡Œã€‚ ### 2. ã€å¼ºåˆ¶ã€‘ 左尿‹¬å·å’Œå—符之间ä¸å‡ºçŽ°ç©ºæ ¼ï¼›åŒæ ·ï¼Œå³å°æ‹¬å·å’Œå—符之间也ä¸å‡ºçŽ°ç©ºæ ¼ã€‚è¯¦è§ ç¬¬ 5 æ¡ä¸‹æ–¹æ£ä¾‹æç¤ºã€‚ å例:if (ç©ºæ ¼ a == b ç©ºæ ¼) ### 3. ã€å¼ºåˆ¶ã€‘if/for/while/switch/do ç‰ä¿ç•™å—与括å·ä¹‹é—´éƒ½å¿…é¡»åŠ ç©ºæ ¼ã€‚ ### 4. ã€å¼ºåˆ¶ã€‘任何二目ã€ä¸‰ç›®è¿ç®—符的左å³ä¸¤è¾¹éƒ½éœ€è¦åŠ ä¸€ä¸ªç©ºæ ¼ã€‚ 说明:è¿ç®—符包括赋值è¿ç®—符=ã€é€»è¾‘è¿ç®—符&&ã€åŠ å‡ä¹˜é™¤ç¬¦å·ç‰ã€‚ ### 5. ã€å¼ºåˆ¶ã€‘采用 4 ä¸ªç©ºæ ¼ç¼©è¿›ï¼Œç¦æ¢ä½¿ç”¨ tab å—符。 说明:如果使用 tab 缩进,必须设置 1 个 tab 为 4 ä¸ªç©ºæ ¼ã€‚IDEA 设置 tab 为 4 ä¸ªç©ºæ ¼æ—¶ï¼Œ 请勿勾选 Use tab character;而在 eclipse ä¸ï¼Œå¿…须勾选 insert spaces for tabs。 æ£ä¾‹ï¼š ï¼ˆæ¶‰åŠ 1-5 点) ``` java public static void main(String[] args) { // 缩进 4 ä¸ªç©ºæ ¼ String say = "hello"; // è¿ç®—符的左å³å¿…é¡»æœ‰ä¸€ä¸ªç©ºæ ¼ int flag = 0; // å…³é”®è¯ if 与括å·ä¹‹é—´å¿…é¡»æœ‰ä¸€ä¸ªç©ºæ ¼ï¼Œæ‹¬å·å†…çš„ f 与左括å·ï¼Œ0 ä¸Žå³æ‹¬å·ä¸éœ€è¦ç©ºæ ¼ if (flag == 0) { System.out.println(say); } // 左大括å·å‰åŠ ç©ºæ ¼ä¸”ä¸æ¢è¡Œï¼›å·¦å¤§æ‹¬å·åŽæ¢è¡Œ if (flag == 1) { System.out.println("world"); // å³å¤§æ‹¬å·å‰æ¢è¡Œï¼Œå³å¤§æ‹¬å·åŽæœ‰ else,ä¸ç”¨æ¢è¡Œ } else { System.out.println("ok"); // 在å³å¤§æ‹¬å·åŽç›´æŽ¥ç»“æŸï¼Œåˆ™å¿…é¡»æ¢è¡Œ } } ``` ### 6. ã€å¼ºåˆ¶ã€‘æ³¨é‡Šçš„åŒæ–œçº¿ä¸Žæ³¨é‡Šå†…å®¹ä¹‹é—´æœ‰ä¸”ä»…æœ‰ä¸€ä¸ªç©ºæ ¼ã€‚ æ£ä¾‹ï¼š// 注释内容,注æ„在//å’Œæ³¨é‡Šå†…å®¹ä¹‹é—´æœ‰ä¸€ä¸ªç©ºæ ¼ã€‚ ### 7. ã€å¼ºåˆ¶ã€‘å•行å—符数é™åˆ¶ä¸è¶…过 120 ä¸ªï¼Œè¶…å‡ºéœ€è¦æ¢è¡Œï¼Œæ¢è¡Œæ—¶éµå¾ªå¦‚下原则: 1) 第二行相对第一行缩进 4 ä¸ªç©ºæ ¼ï¼Œä»Žç¬¬ä¸‰è¡Œå¼€å§‹ï¼Œä¸å†ç»§ç»ç¼©è¿›ï¼Œå‚考示例。 2) è¿ç®—符与下文一起æ¢è¡Œã€‚ 3) 方法调用的点符å·ä¸Žä¸‹æ–‡ä¸€èµ·æ¢è¡Œã€‚ 4) æ–¹æ³•è°ƒç”¨æ—¶ï¼Œå¤šä¸ªå‚æ•°ï¼Œéœ€è¦æ¢è¡Œæ—¶ï¼Œåœ¨é€—å·åŽè¿›è¡Œã€‚ 5) 在括å·å‰ä¸è¦æ¢è¡Œï¼Œè§å例。 æ£ä¾‹ï¼š ``` java StringBuffer sb = new StringBuffer(); // 超过 120 个å—符的情况下,æ¢è¡Œç¼©è¿› 4 ä¸ªç©ºæ ¼ï¼Œç‚¹å·å’Œæ–¹æ³•å称一起æ¢è¡Œ sb.append("zi").append("xin")... .append("huang")... .append("huang")... .append("huang"); ``` å例: ``` java StringBuffer sb = new StringBuffer(); // 超过 120 个å—符的情况下,ä¸è¦åœ¨æ‹¬å·å‰æ¢è¡Œ sb.append("zi").append("xin")...append ("huang"); // 傿•°å¾ˆå¤šçš„æ–¹æ³•调用å¯èƒ½è¶…过 120 个å—符,ä¸è¦åœ¨é€—å·å‰æ¢è¡Œ method(args1, args2, args3, ... , argsX); ``` ### 8. ã€å¼ºåˆ¶ã€‘æ–¹æ³•å‚æ•°åœ¨å®šä¹‰å’Œä¼ å…¥æ—¶ï¼Œå¤šä¸ªå‚æ•°é€—å·åŽè¾¹å¿…é¡»åŠ ç©ºæ ¼ã€‚ æ£ä¾‹ï¼šä¸‹ä¾‹ä¸å®žå‚çš„"a",åŽè¾¹å¿…é¡»è¦æœ‰ä¸€ä¸ªç©ºæ ¼ã€‚ ``` java method("a", "b", "c"); ``` ### 9. ã€å¼ºåˆ¶ã€‘IDE çš„ text file encoding 设置为 UTF-8; IDE 䏿–‡ä»¶çš„æ¢è¡Œç¬¦ä½¿ç”¨ Unix æ ¼å¼ï¼Œä¸è¦ä½¿ç”¨ Windows æ ¼å¼ã€‚ ### 10. ã€æŽ¨è】没有必è¦å¢žåŠ è‹¥å¹²ç©ºæ ¼æ¥ä½¿æŸä¸€è¡Œçš„å—符与上一行对应ä½ç½®çš„å—符对é½ã€‚ æ£ä¾‹ï¼š ``` java int a = 3; long b = 4L; float c = 5F; StringBuffer sb = new StringBuffer(); ``` è¯´æ˜Žï¼šå¢žåŠ sb 这个å˜é‡ï¼Œå¦‚果需è¦å¯¹é½ï¼Œåˆ™ç»™ aã€bã€c 都è¦å¢žåŠ å‡ ä¸ªç©ºæ ¼ï¼Œåœ¨å˜é‡æ¯”较多的 情况下,是一ç§ç´¯èµ˜çš„事情。 ### 11. ã€æŽ¨è】方法体内的执行è¯å¥ç»„ã€å˜é‡çš„定义è¯å¥ç»„ã€ä¸åŒçš„业务逻辑之间或者ä¸åŒçš„è¯ä¹‰ 之间æ’入一个空行。相åŒä¸šåŠ¡é€»è¾‘å’Œè¯ä¹‰ä¹‹é—´ä¸éœ€è¦æ’入空行。 è¯´æ˜Žï¼šæ²¡æœ‰å¿…è¦æ’入多个空行进行隔开。 ## (å››)OOP 规约 ### ### 1. ã€å¼ºåˆ¶ã€‘é¿å…通过一个类的对象引用访问æ¤ç±»çš„陿€å˜é‡æˆ–陿€æ–¹æ³•ï¼Œæ— è°“å¢žåŠ ç¼–è¯‘å™¨è§£æžæˆ æœ¬ï¼Œç›´æŽ¥ç”¨ç±»åæ¥è®¿é—®å³å¯ã€‚ ### ### 2. ã€å¼ºåˆ¶ã€‘æ‰€æœ‰çš„è¦†å†™æ–¹æ³•ï¼Œå¿…é¡»åŠ @Override 注解。 说明:getObject()与 get0bject()çš„é—®é¢˜ã€‚ä¸€ä¸ªæ˜¯å—æ¯çš„ O,一个是数å—çš„ 0ï¼ŒåŠ @Override å¯ä»¥å‡†ç¡®åˆ¤æ–是å¦è¦†ç›–æˆåŠŸã€‚å¦å¤–,如果在抽象类ä¸å¯¹æ–¹æ³•ç¾å进行修改,其实现类会马上编 译报错。 ### 3. ã€å¼ºåˆ¶ã€‘相åŒå‚数类型,相åŒä¸šåŠ¡å«ä¹‰ï¼Œæ‰å¯ä»¥ä½¿ç”¨ Java çš„å¯å˜å‚数,é¿å…使用 Object。 说明:å¯å˜å‚æ•°å¿…é¡»æ”¾ç½®åœ¨å‚æ•°åˆ—表的最åŽã€‚(æå€¡åŒå¦ä»¬å°½é‡ä¸ç”¨å¯å˜å‚数编程) æ£ä¾‹ï¼špublic User getUsers(String type, Integer... ids) {...} ### 4. ã€å¼ºåˆ¶ã€‘外部æ£åœ¨è°ƒç”¨æˆ–者二方库ä¾èµ–的接å£ï¼Œä¸å…许修改方法ç¾å,é¿å…对接å£è°ƒç”¨æ–¹äº§ç”Ÿ å½±å“。接å£è¿‡æ—¶å¿…é¡»åŠ @Deprecated æ³¨è§£ï¼Œå¹¶æ¸…æ™°åœ°è¯´æ˜Žé‡‡ç”¨çš„æ–°æŽ¥å£æˆ–者新æœåŠ¡æ˜¯ä»€ä¹ˆã€‚ ### 5. ã€å¼ºåˆ¶ã€‘ä¸èƒ½ä½¿ç”¨è¿‡æ—¶çš„类或方法。 说明:java.net.URLDecoder ä¸çš„æ–¹æ³• decode(String encodeStr) 这个方法已ç»è¿‡æ—¶ï¼Œåº” 该使用åŒå‚æ•° decode(String source, String encode)ã€‚æŽ¥å£æä¾›æ–¹æ—¢ç„¶æ˜Žç¡®æ˜¯è¿‡æ—¶æŽ¥å£ï¼Œ é‚£ä¹ˆæœ‰ä¹‰åŠ¡åŒæ—¶æä¾›æ–°çš„æŽ¥å£ï¼›ä½œä¸ºè°ƒç”¨æ–¹æ¥è¯´ï¼Œæœ‰ä¹‰åŠ¡åŽ»è€ƒè¯è¿‡æ—¶æ–¹æ³•的新实现是什么。 ### 6. ã€å¼ºåˆ¶ã€‘Object çš„ equals æ–¹æ³•å®¹æ˜“æŠ›ç©ºæŒ‡é’ˆå¼‚å¸¸ï¼Œåº”ä½¿ç”¨å¸¸é‡æˆ–确定有值的对象æ¥è°ƒç”¨ equals。 æ£ä¾‹ï¼š ``` java "test".equals(object); ``` å例: ``` java object.equals("test"); ``` 说明:推è使用 java.util.Objects#equals(JDK7 引入的工具类) ### 7. ã€å¼ºåˆ¶ã€‘所有的相åŒç±»åž‹çš„包装类对象之间值的比较,全部使用 equals 方法比较。 说明:对于 Integer var = ? 在-128 至 127 范围内的赋值,Integer 对象是在IntegerCache.cache 产生,会å¤ç”¨å·²æœ‰å¯¹è±¡ï¼Œè¿™ä¸ªåŒºé—´å†…çš„ Integer 值å¯ä»¥ç›´æŽ¥ä½¿ç”¨==进行 判æ–,但是这个区间之外的所有数æ®ï¼Œéƒ½ä¼šåœ¨å †ä¸Šäº§ç”Ÿï¼Œå¹¶ä¸ä¼šå¤ç”¨å·²æœ‰å¯¹è±¡ï¼Œè¿™æ˜¯ä¸€ä¸ªå¤§å‘, 推è使用 equals 方法进行判æ–。 ### 8. 关于基本数æ®ç±»åž‹ä¸ŽåŒ…装数æ®ç±»åž‹çš„ä½¿ç”¨æ ‡å‡†å¦‚ä¸‹ï¼š 1) ã€å¼ºåˆ¶ã€‘所有的 POJO 类属性必须使用包装数æ®ç±»åž‹ã€‚ 2) ã€å¼ºåˆ¶ã€‘RPC æ–¹æ³•çš„è¿”å›žå€¼å’Œå‚æ•°å¿…须使用包装数æ®ç±»åž‹ã€‚ 3) ã€æŽ¨è】所有的局部å˜é‡ä½¿ç”¨åŸºæœ¬æ•°æ®ç±»åž‹ã€‚ 说明:POJO 类属性没有åˆå€¼æ˜¯æé†’使用者在需è¦ä½¿ç”¨æ—¶ï¼Œå¿…须自己显å¼åœ°è¿›è¡Œèµ‹å€¼ï¼Œä»»ä½• NPE 问题,或者入库检查,都由使用者æ¥ä¿è¯ã€‚ æ£ä¾‹ï¼šæ•°æ®åº“的查询结果å¯èƒ½æ˜¯ nullï¼Œå› ä¸ºè‡ªåŠ¨æ‹†ç®±ï¼Œç”¨åŸºæœ¬æ•°æ®ç±»åž‹æŽ¥æ”¶æœ‰ NPE 风险。 å例:比如显示æˆäº¤æ€»é¢æ¶¨è·Œæƒ…å†µï¼Œå³æ£è´Ÿ x%,x 为基本数æ®ç±»åž‹ï¼Œè°ƒç”¨çš„ RPC æœåŠ¡ï¼Œè°ƒç”¨ 䏿ˆåŠŸæ—¶ï¼Œè¿”å›žçš„æ˜¯é»˜è®¤å€¼ï¼Œé¡µé¢æ˜¾ç¤ºä¸º 0%,这是ä¸åˆç†çš„,应该显示æˆä¸åˆ’线。所以包装 æ•°æ®ç±»åž‹çš„ null 值,能够表示é¢å¤–的信æ¯ï¼Œå¦‚:远程调用失败,异常退出。 ### 9. ã€å¼ºåˆ¶ã€‘定义 DO/DTO/VO ç‰ POJO 类时,ä¸è¦è®¾å®šä»»ä½•属性默认值。 å例:POJO 类的 gmtCreate 默认值为 new Date();ä½†æ˜¯è¿™ä¸ªå±žæ€§åœ¨æ•°æ®æå–æ—¶å¹¶æ²¡æœ‰ç½®å…¥å…· ä½“å€¼ï¼Œåœ¨æ›´æ–°å…¶å®ƒå—æ®µæ—¶åˆé™„带更新了æ¤å—段,导致创建时间被修改æˆå½“剿—¶é—´ã€‚ ### 10. ã€å¼ºåˆ¶ã€‘åºåˆ—化类新增属性时,请ä¸è¦ä¿®æ”¹ serialVersionUID å—æ®µï¼Œé¿å…ååºåˆ—失败;如 果完全ä¸å…¼å®¹å‡çº§ï¼Œé¿å…ååºåˆ—化混乱,那么请修改 serialVersionUID 值。 è¯´æ˜Žï¼šæ³¨æ„ serialVersionUID ä¸ä¸€è‡´ä¼šæŠ›å‡ºåºåˆ—化è¿è¡Œæ—¶å¼‚常。 ### 11. ã€å¼ºåˆ¶ã€‘æž„é€ æ–¹æ³•é‡Œé¢ç¦æ¢åŠ å…¥ä»»ä½•ä¸šåŠ¡é€»è¾‘ï¼Œå¦‚æžœæœ‰åˆå§‹åŒ–逻辑,请放在 init 方法ä¸ã€‚ ### 12. ã€å¼ºåˆ¶ã€‘POJO 类必须写 toString 方法。使用 IDE çš„ä¸å·¥å…·ï¼šsource> generate toString 时,如果继承了å¦ä¸€ä¸ª POJO 类,注æ„在å‰é¢åР䏀䏋 super.toString。 说明:在方法执行抛出异常时,å¯ä»¥ç›´æŽ¥è°ƒç”¨ POJO çš„ toString()方法打å°å…¶å±žæ€§å€¼ï¼Œä¾¿äºŽæŽ’ 查问题。 ### 13. ã€æŽ¨è】使用索引访问用 String çš„ split æ–¹æ³•å¾—åˆ°çš„æ•°ç»„æ—¶ï¼Œéœ€åšæœ€åŽä¸€ä¸ªåˆ†éš”ç¬¦åŽæœ‰æ— 内容的检查,å¦åˆ™ä¼šæœ‰æŠ› IndexOutOfBoundsException 的风险。 说明: ``` java String str = "a,b,c,,"; String[] ary = str.split(","); // 预期大于 3,结果是 3 System.out.println(ary.length); ``` ### 14. ã€æŽ¨èã€‘å½“ä¸€ä¸ªç±»æœ‰å¤šä¸ªæž„é€ æ–¹æ³•ï¼Œæˆ–è€…å¤šä¸ªåŒåæ–¹æ³•ï¼Œè¿™äº›æ–¹æ³•åº”è¯¥æŒ‰é¡ºåºæ”¾ç½®åœ¨ä¸€èµ·ï¼Œ ä¾¿äºŽé˜…è¯»ï¼Œæ¤æ¡è§„则优先于第 15 æ¡è§„则。 ### 15. ã€æŽ¨è】 类内方法定义顺åºä¾æ¬¡æ˜¯ï¼šå…¬æœ‰æ–¹æ³•æˆ–ä¿æŠ¤æ–¹æ³• > ç§æœ‰æ–¹æ³• > getter/setter方法。 说明:公有方法是类的调用者和维护者最关心的方法,首å±å±•ç¤ºæœ€å¥½ï¼›ä¿æŠ¤æ–¹æ³•è™½ç„¶åªæ˜¯åç±» 关心,也å¯èƒ½æ˜¯â€œæ¨¡æ¿è®¾è®¡æ¨¡å¼â€ä¸‹çš„æ ¸å¿ƒæ–¹æ³•ï¼›è€Œç§æœ‰æ–¹æ³•外部一般ä¸éœ€è¦ç‰¹åˆ«å…³å¿ƒï¼Œæ˜¯ä¸€ä¸ª é»‘ç›’å®žçŽ°ï¼›å› ä¸ºæ‰¿è½½çš„ä¿¡æ¯ä»·å€¼è¾ƒä½Žï¼Œæ‰€æœ‰ Service å’Œ DAO çš„ getter/setter 方法放在类体 最åŽã€‚ ### 16. ã€æŽ¨è】setter 方法ä¸ï¼Œå‚æ•°å称与类æˆå‘˜å˜é‡å称一致,this.æˆå‘˜å = 傿•°å。在 getter/setter 方法ä¸ï¼Œä¸è¦å¢žåŠ ä¸šåŠ¡é€»è¾‘ï¼Œå¢žåŠ æŽ’æŸ¥é—®é¢˜çš„éš¾åº¦ã€‚ å例: ``` java public Integer getData() { if (true) { return this.data + 100; } else { return this.data - 100; } } ``` ### 17. ã€æŽ¨è】循环体内,å—符串的连接方å¼ï¼Œä½¿ç”¨ StringBuilder çš„ append 方法进行扩展。 说明:å编译出的å—èŠ‚ç æ–‡ä»¶æ˜¾ç¤ºæ¯æ¬¡å¾ªçŽ¯éƒ½ä¼š new 出一个 StringBuilder 对象,然åŽè¿›è¡Œ append æ“作,最åŽé€šè¿‡ toString 方法返回 String å¯¹è±¡ï¼Œé€ æˆå†…å˜èµ„æºæµªè´¹ã€‚ å例: ``` java String str = "start"; for (int i = 0; i < 100; i++) { str = str + "hello"; } ``` ### 18. ã€æŽ¨è】final å¯ä»¥å£°æ˜Žç±»ã€æˆå‘˜å˜é‡ã€æ–¹æ³•ã€ä»¥åŠæœ¬åœ°å˜é‡ï¼Œä¸‹åˆ—情况使用 final 关键å—: 1) ä¸å…许被继承的类,如:String 类。 2) ä¸å…许修改引用的域对象,如:POJO 类的域å˜é‡ã€‚ 3) ä¸å…许被é‡å†™çš„æ–¹æ³•,如:POJO 类的 setter 方法。 4) ä¸å…许è¿è¡Œè¿‡ç¨‹ä¸é‡æ–°èµ‹å€¼çš„局部å˜é‡ã€‚ 5) é¿å…上下文é‡å¤ä½¿ç”¨ä¸€ä¸ªå˜é‡ï¼Œä½¿ç”¨ final æè¿°å¯ä»¥å¼ºåˆ¶é‡æ–°å®šä¹‰ä¸€ä¸ªå˜é‡ï¼Œæ–¹ä¾¿æ›´å¥½ åœ°è¿›è¡Œé‡æž„。 ### 19. ã€æŽ¨è】慎用 Object çš„ clone æ–¹æ³•æ¥æ‹·è´å¯¹è±¡ã€‚ 说明:对象的 clone 方法默认是浅拷è´ï¼Œè‹¥æƒ³å®žçŽ°æ·±æ‹·è´éœ€è¦é‡å†™ clone 方法实现属性对象 的拷è´ã€‚ ### 20. ã€æŽ¨è】类æˆå‘˜ä¸Žæ–¹æ³•访问控制从严: 1) 如果ä¸å…许外部直接通过 new æ¥åˆ›å»ºå¯¹è±¡ï¼Œé‚£ä¹ˆæž„é€ æ–¹æ³•å¿…é¡»æ˜¯ private。 2) 工具类ä¸å…许有 public 或 default æž„é€ æ–¹æ³•ã€‚ 3) ç±»éž static æˆå‘˜å˜é‡å¹¶ä¸”与å类共享,必须是 protected。 4) ç±»éž static æˆå‘˜å˜é‡å¹¶ä¸”仅在本类使用,必须是 private。 5) ç±» static æˆå‘˜å˜é‡å¦‚果仅在本类使用,必须是 private。 6) 若是 static æˆå‘˜å˜é‡ï¼Œå¿…须考虑是å¦ä¸º final。 7) ç±»æˆå‘˜æ–¹æ³•åªä¾›ç±»å†…部调用,必须是 private。 8) ç±»æˆå‘˜æ–¹æ³•åªå¯¹ç»§æ‰¿ç±»å…¬å¼€ï¼Œé‚£ä¹ˆé™åˆ¶ä¸º protected。 è¯´æ˜Žï¼šä»»ä½•ç±»ã€æ–¹æ³•ã€å‚æ•°ã€å˜é‡ï¼Œä¸¥æŽ§è®¿é—®èŒƒå›´ã€‚过于宽泛的访问范围,ä¸åˆ©äºŽæ¨¡å—解耦。 æ€è€ƒï¼šå¦‚果是一个 private çš„æ–¹æ³•ï¼Œæƒ³åˆ é™¤å°±åˆ é™¤ï¼Œå¯æ˜¯ä¸€ä¸ª public çš„ service 方法,或者 一个 public çš„æˆå‘˜å˜é‡ï¼Œåˆ 除一下,ä¸å¾—手心冒点汗å—?å˜é‡åƒè‡ªå·±çš„å°å©ï¼Œå°½é‡åœ¨è‡ªå·±çš„ 视线内,å˜é‡ä½œç”¨åŸŸå¤ªå¤§ï¼Œæ— é™åˆ¶çš„åˆ°å¤„è·‘ï¼Œé‚£ä¹ˆä½ ä¼šæ‹…å¿ƒçš„ã€‚ ## (五)集åˆå¤„ç† ### 1. ã€å¼ºåˆ¶ã€‘关于 hashCode å’Œ equals 的处ç†ï¼Œéµå¾ªå¦‚下规则: 1) åªè¦é‡å†™ equals,就必须é‡å†™ hashCode。 2) å› ä¸º Set å˜å‚¨çš„æ˜¯ä¸é‡å¤çš„å¯¹è±¡ï¼Œä¾æ® hashCode å’Œ equals 进行判æ–,所以 Set å˜å‚¨çš„ 对象必须é‡å†™è¿™ä¸¤ä¸ªæ–¹æ³•。 3) 如果自定义对象åšä¸º Map 的键,那么必须é‡å†™ hashCode å’Œ equals。 说明:String é‡å†™äº† hashCode å’Œ equals 方法,所以我们å¯ä»¥éžå¸¸æ„‰å¿«åœ°ä½¿ç”¨ String 对象 作为 key æ¥ä½¿ç”¨ã€‚ ### 2. ã€å¼ºåˆ¶ã€‘ArrayListçš„subList结果ä¸å¯å¼ºè½¬æˆArrayList,å¦åˆ™ä¼šæŠ›å‡ºClassCastException å¼‚å¸¸ï¼Œå³ java.util.RandomAccessSubList cannot be cast to java.util.ArrayList. 说明:subList 返回的是 ArrayList 的内部类 SubListï¼Œå¹¶ä¸æ˜¯ ArrayList ,而是 ArrayList 的一个视图,对于 SubList å列表的所有æ“ä½œæœ€ç»ˆä¼šåæ˜ 到原列表上。 ### 3. ã€å¼ºåˆ¶ã€‘在 subList 场景ä¸ï¼Œé«˜åº¦æ³¨æ„对原集åˆå…ƒç´ 个数的修改,会导致å列表的é历ã€å¢žåŠ ã€ åˆ é™¤å‡ä¼šäº§ç”Ÿ ConcurrentModificationException 异常。 ### 4. ã€å¼ºåˆ¶ã€‘使用集åˆè½¬æ•°ç»„的方法,必须使用集åˆçš„ toArray(T[] array)ï¼Œä¼ å…¥çš„æ˜¯ç±»åž‹å®Œå…¨ ä¸€æ ·çš„æ•°ç»„ï¼Œå¤§å°å°±æ˜¯ list.size()。 说明:使用 toArray 另傿–¹æ³•,入å‚分é…的数组空间ä¸å¤Ÿå¤§æ—¶ï¼ŒtoArray æ–¹æ³•å†…éƒ¨å°†é‡æ–°åˆ†é… 内å˜ç©ºé—´ï¼Œå¹¶è¿”回新数组地å€ï¼›å¦‚æžœæ•°ç»„å…ƒç´ å¤§äºŽå®žé™…æ‰€éœ€ï¼Œä¸‹æ ‡ä¸º[ list.size() ]的数组 å…ƒç´ å°†è¢«ç½®ä¸º nullï¼Œå…¶å®ƒæ•°ç»„å…ƒç´ ä¿æŒåŽŸå€¼ï¼Œå› æ¤æœ€å¥½å°†æ–¹æ³•入傿•°ç»„大å°å®šä¹‰ä¸Žé›†åˆå…ƒç´ 个数一致。 æ£ä¾‹ï¼š ``` java List<String> list = new ArrayList<String>(2); list.add("guan"); list.add("bao"); String[] array = new String[list.size()]; array = list.toArray(array); ``` å例:直接使用 toArray æ— å‚æ–¹æ³•å˜åœ¨é—®é¢˜ï¼Œæ¤æ–¹æ³•返回值åªèƒ½æ˜¯ Object[]类,若强转其它 类型数组将出现 ClassCastException 错误。 ### 5. ã€å¼ºåˆ¶ã€‘使用工具类 Arrays.asList()æŠŠæ•°ç»„è½¬æ¢æˆé›†åˆæ—¶ï¼Œä¸èƒ½ä½¿ç”¨å…¶ä¿®æ”¹é›†åˆç›¸å…³çš„æ–¹ 法,它的 add/remove/clear 方法会抛出 UnsupportedOperationException 异常。 说明:asList 的返回对象是一个 Arrays 内部类,并没有实现集åˆçš„修改方法。Arrays.asList 体现的是适é…器模å¼ï¼Œåªæ˜¯è½¬æ¢æŽ¥å£ï¼ŒåŽå°çš„æ•°æ®ä»æ˜¯æ•°ç»„。 ``` java String[] str = new String[] { "you", "wu" }; List list = Arrays.asList(str); ``` ç¬¬ä¸€ç§æƒ…况:list.add("yangguanbao"); è¿è¡Œæ—¶å¼‚常。 ç¬¬äºŒç§æƒ…况:str[0] = "gujin"; 那么 list.get(0)也会éšä¹‹ä¿®æ”¹ã€‚ ### 6. ã€å¼ºåˆ¶ã€‘泛型通é…符<? extends T>æ¥æŽ¥æ”¶è¿”å›žçš„æ•°æ®ï¼Œæ¤å†™æ³•的泛型集åˆä¸èƒ½ä½¿ç”¨ add æ–¹ 法,而<? super T>ä¸èƒ½ä½¿ç”¨ get 方法,åšä¸ºæŽ¥å£è°ƒç”¨èµ‹å€¼æ—¶æ˜“出错。 说明:扩展说一下 PECS(Producer Extends Consumer Super)原则:第一ã€é¢‘ç¹å¾€å¤–读å–内 容的,适åˆç”¨<? extends T>。第二ã€ç»å¸¸å¾€é‡Œæ’入的,适åˆç”¨<? super T>。 ### 7. ã€å¼ºåˆ¶ã€‘ä¸è¦åœ¨ foreach å¾ªçŽ¯é‡Œè¿›è¡Œå…ƒç´ çš„ remove/add æ“作。remove å…ƒç´ è¯·ä½¿ç”¨ Iterator æ–¹å¼ï¼Œå¦‚æžœå¹¶å‘æ“作,需è¦å¯¹ Iterator å¯¹è±¡åŠ é”。 æ£ä¾‹ï¼š ``` java Iterator<String> iterator = list.iterator(); while (iterator.hasNext()) { String item = iterator.next(); if (åˆ é™¤å…ƒç´ çš„æ¡ä»¶) { iterator.remove(); } } ``` å例: ``` java List<String> list = new ArrayList<String>(); list.add("1"); list.add("2"); for (String item : list) { if ("1".equals(item)) { list.remove(item); } } ``` 说明:以上代ç çš„æ‰§è¡Œç»“æžœè‚¯å®šä¼šå‡ºä¹Žå¤§å®¶çš„æ„æ–™ï¼Œé‚£ä¹ˆè¯•一下把“1â€æ¢æˆâ€œ2â€ï¼Œä¼šæ˜¯åŒæ ·çš„ 结果å—? ### 8. ã€å¼ºåˆ¶ã€‘ 在 JDK7 版本åŠä»¥ä¸Šï¼ŒComparator è¦æ»¡è¶³å¦‚下三个æ¡ä»¶ï¼Œä¸ç„¶ Arrays.sort, Collections.sort 会报 IllegalArgumentException 异常。 说明:三个æ¡ä»¶å¦‚下 1) x,y 的比较结果和 y,x 的比较结果相å。 2) x>y,y>z,则 x>z。 3) x=y,则 x,z 比较结果和 y,z 比较结果相åŒã€‚ åä¾‹ï¼šä¸‹ä¾‹ä¸æ²¡æœ‰å¤„ç†ç›¸ç‰çš„æƒ…况,实际使用ä¸å¯èƒ½ä¼šå‡ºçŽ°å¼‚å¸¸ï¼š ``` java new Comparator<Student>() { @Override public int compare(Student o1, Student o2) { return o1.getId() > o2.getId() ? 1 : -1; } }; ``` ### 9. ã€æŽ¨è】集åˆåˆå§‹åŒ–时,指定集åˆåˆå§‹å€¼å¤§å°ã€‚ 说明:HashMap 使用 HashMap(int initialCapacity) åˆå§‹åŒ–, æ£ä¾‹ï¼šinitialCapacity = (需è¦å˜å‚¨çš„å…ƒç´ ä¸ªæ•° / è´Ÿè½½å› å) + 1。注æ„è´Ÿè½½å› åï¼ˆå³ loader factor)默认为 0.75ï¼Œå¦‚æžœæš‚æ—¶æ— æ³•ç¡®å®šåˆå§‹å€¼å¤§å°ï¼Œè¯·è®¾ç½®ä¸º 16(å³é»˜è®¤å€¼ï¼‰ã€‚ å例:HashMap éœ€è¦æ”¾ç½® 1024 ä¸ªå…ƒç´ ï¼Œç”±äºŽæ²¡æœ‰è®¾ç½®å®¹é‡åˆå§‹å¤§å°ï¼Œéšç€å…ƒç´ 䏿–å¢žåŠ ï¼Œå®¹ é‡ 7 次被迫扩大,resize 需è¦é‡å»º hash 表,严é‡å½±å“性能。 ### 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 é”分段技术(JDK8:CAS) TreeMap ä¸å…许为 null å…许为 null AbstractMap 线程ä¸å®‰å…¨ HashMap å…许为 null å…许为 null AbstractMap 线程ä¸å®‰å…¨ å例: 由于 HashMap 的干扰,很多人认为 ConcurrentHashMap 是å¯ä»¥ç½®å…¥ null 值,而事实上, å˜å‚¨ null 值时会抛出 NPE 异常。 ### 12. ã€å‚考】åˆç†åˆ©ç”¨å¥½é›†åˆçš„æœ‰åºæ€§(sort)和稳定性(order),é¿å…集åˆçš„æ— åºæ€§(unsort)å’Œ ä¸ç¨³å®šæ€§(unorder)带æ¥çš„è´Ÿé¢å½±å“。 è¯´æ˜Žï¼šæœ‰åºæ€§æ˜¯æŒ‡é历的结果是按æŸç§æ¯”è¾ƒè§„åˆ™ä¾æ¬¡æŽ’åˆ—çš„ã€‚ç¨³å®šæ€§æŒ‡é›†åˆæ¯æ¬¡éåŽ†çš„å…ƒç´ æ¬¡ åºæ˜¯ä¸€å®šçš„。如:ArrayList 是 order/unsortï¼›HashMap 是 unorder/unsortï¼›TreeSet 是 order/sort。 ### 13. ã€å‚考】利用 Set å…ƒç´ å”¯ä¸€çš„ç‰¹æ€§ï¼Œå¯ä»¥å¿«é€Ÿå¯¹ä¸€ä¸ªé›†åˆè¿›è¡Œå޻釿“作,é¿å…使用 List çš„ contains 方法进行é历ã€å¯¹æ¯”ã€å޻釿“作。 ## (å…)å¹¶å‘å¤„ç† ### 1. ã€å¼ºåˆ¶ã€‘获å–å•例对象需è¦ä¿è¯çº¿ç¨‹å®‰å…¨ï¼Œå…¶ä¸çš„æ–¹æ³•也è¦ä¿è¯çº¿ç¨‹å®‰å…¨ã€‚ 说明:资æºé©±åŠ¨ç±»ã€å·¥å…·ç±»ã€å•ä¾‹å·¥åŽ‚ç±»éƒ½éœ€è¦æ³¨æ„。 ### 2. ã€å¼ºåˆ¶ã€‘åˆ›å»ºçº¿ç¨‹æˆ–çº¿ç¨‹æ± æ—¶è¯·æŒ‡å®šæœ‰æ„义的线程å称,方便出错时回溯。 æ£ä¾‹ï¼š ``` java public class TimerTaskThread extends Thread { public TimerTaskThread() { super.setName("TimerTaskThread"); ... } } ``` ### 3. ã€å¼ºåˆ¶ã€‘线程资æºå¿…é¡»é€šè¿‡çº¿ç¨‹æ± æä¾›ï¼Œä¸å…许在应用ä¸è‡ªè¡Œæ˜¾å¼åˆ›å»ºçº¿ç¨‹ã€‚ è¯´æ˜Žï¼šä½¿ç”¨çº¿ç¨‹æ± çš„å¥½å¤„æ˜¯å‡å°‘在创建和销æ¯çº¿ç¨‹ä¸Šæ‰€èŠ±çš„æ—¶é—´ä»¥åŠç³»ç»Ÿèµ„æºçš„开销,解决资 æºä¸è¶³çš„问题。如果ä¸ä½¿ç”¨çº¿ç¨‹æ± ,有å¯èƒ½é€ æˆç³»ç»Ÿåˆ›å»ºå¤§é‡åŒç±»çº¿ç¨‹è€Œå¯¼è‡´æ¶ˆè€—å®Œå†…å˜æˆ–者 “过度切æ¢â€çš„问题。 ### 4. ã€å¼ºåˆ¶ã€‘çº¿ç¨‹æ± ä¸å…许使用 Executors 去创建,而是通过 ThreadPoolExecutor 的方å¼ï¼Œè¿™æ · çš„å¤„ç†æ–¹å¼è®©å†™çš„åŒå¦æ›´åŠ æ˜Žç¡®çº¿ç¨‹æ± çš„è¿è¡Œè§„则,规é¿èµ„æºè€—尽的风险。 说明:Executors è¿”å›žçš„çº¿ç¨‹æ± å¯¹è±¡çš„å¼Šç«¯å¦‚ä¸‹ï¼š 1)FixedThreadPool å’Œ SingleThreadPool: å…许的请求队列长度为 Integer.MAX_VALUE,å¯èƒ½ä¼šå †ç§¯å¤§é‡çš„请求,从而导致 OOM。 2)CachedThreadPool å’Œ ScheduledThreadPool: å…许的创建线程数é‡ä¸º Integer.MAX_VALUE,å¯èƒ½ä¼šåˆ›å»ºå¤§é‡çš„线程,从而导致 OOM。 ### 5. ã€å¼ºåˆ¶ã€‘SimpleDateFormat 是线程ä¸å®‰å…¨çš„类,一般ä¸è¦å®šä¹‰ä¸º static å˜é‡ï¼Œå¦‚果定义为 staticï¼Œå¿…é¡»åŠ é”,或者使用 DateUtils 工具类。 æ£ä¾‹ï¼šæ³¨æ„线程安全,使用 DateUtils。亦推è如下处ç†ï¼š ``` java 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 代替 SimpleDateFormat,官方给出的解释:simple beautiful strong immutable thread-safe。 ### 6. ã€å¼ºåˆ¶ã€‘é«˜å¹¶å‘æ—¶ï¼ŒåŒæ¥è°ƒç”¨åº”该去考é‡é”的性能æŸè€—ã€‚èƒ½ç”¨æ— é”æ•°æ®ç»“构,就ä¸è¦ç”¨é”;能 é”区å—,就ä¸è¦é”整个方法体;能用对象é”,就ä¸è¦ç”¨ç±»é”。 说明:尽å¯èƒ½ä½¿åŠ é”的代ç å—工作é‡å°½å¯èƒ½çš„å°ï¼Œé¿å…在é”代ç å—ä¸è°ƒç”¨ RPC 方法。 ### 7. ã€å¼ºåˆ¶ã€‘对多个资æºã€æ•°æ®åº“表ã€å¯¹è±¡åŒæ—¶åР锿—¶ï¼Œéœ€è¦ä¿æŒä¸€è‡´çš„åŠ é”顺åºï¼Œå¦åˆ™å¯èƒ½ä¼šé€ æˆæ»é”。 说明:线程一需è¦å¯¹è¡¨ Aã€Bã€C 便¬¡å…¨éƒ¨åŠ é”åŽæ‰å¯ä»¥è¿›è¡Œæ›´æ–°æ“ä½œï¼Œé‚£ä¹ˆçº¿ç¨‹äºŒçš„åŠ é”é¡ºåº ä¹Ÿå¿…é¡»æ˜¯ Aã€Bã€C,å¦åˆ™å¯èƒ½å‡ºçްæ»é”。 ### 8. ã€å¼ºåˆ¶ã€‘å¹¶å‘修改åŒä¸€è®°å½•时,é¿å…更新丢失,需è¦åŠ é”。è¦ä¹ˆåœ¨åº”ç”¨å±‚åŠ é”,è¦ä¹ˆåœ¨ç¼“å˜åŠ é”,è¦ä¹ˆåœ¨æ•°æ®åº“层使用ä¹è§‚é”,使用 version ä½œä¸ºæ›´æ–°ä¾æ®ã€‚ è¯´æ˜Žï¼šå¦‚æžœæ¯æ¬¡è®¿é—®å†²çªæ¦‚率å°äºŽ 20%,推è使用ä¹è§‚é”,å¦åˆ™ä½¿ç”¨æ‚²è§‚é”。ä¹è§‚é”çš„é‡è¯•次 æ•°ä¸å¾—å°äºŽ 3 次。 ### 9. ã€å¼ºåˆ¶ã€‘多线程并行处ç†å®šæ—¶ä»»åŠ¡æ—¶ï¼ŒTimer è¿è¡Œå¤šä¸ª TimeTask 时,åªè¦å…¶ä¸ä¹‹ä¸€æ²¡æœ‰æ•获 抛出的异常,其它任务便会自动终æ¢è¿è¡Œï¼Œä½¿ç”¨ ScheduledExecutorService 则没有这个问题。 ### 10. ã€æŽ¨è】使用 CountDownLatch 进行异æ¥è½¬åŒæ¥æ“作,æ¯ä¸ªçº¿ç¨‹é€€å‡ºå‰å¿…须调用 countDown æ–¹æ³•ï¼Œçº¿ç¨‹æ‰§è¡Œä»£ç æ³¨æ„ catch å¼‚å¸¸ï¼Œç¡®ä¿ countDown 方法被执行到,é¿å…ä¸»çº¿ç¨‹æ— æ³•æ‰§è¡Œ 至 await 方法,直到超时æ‰è¿”回结果。 说明:注æ„,åçº¿ç¨‹æŠ›å‡ºå¼‚å¸¸å †æ ˆï¼Œä¸èƒ½åœ¨ä¸»çº¿ç¨‹ try-catch 到。 ### 11. ã€æŽ¨è】é¿å… Random å®žä¾‹è¢«å¤šçº¿ç¨‹ä½¿ç”¨ï¼Œè™½ç„¶å…±äº«è¯¥å®žä¾‹æ˜¯çº¿ç¨‹å®‰å…¨çš„ï¼Œä½†ä¼šå› ç«žäº‰åŒä¸€ seed 导致的性能下é™ã€‚ 说明:Random 实例包括 java.util.Random 的实例或者 Math.random()的方å¼ã€‚ æ£ä¾‹ï¼šåœ¨ JDK7 之åŽï¼Œå¯ä»¥ç›´æŽ¥ä½¿ç”¨ API ThreadLocalRandom,而在 JDK7 之å‰ï¼Œéœ€è¦ç¼–ç ä¿ è¯æ¯ä¸ªçº¿ç¨‹æŒæœ‰ä¸€ä¸ªå®žä¾‹ã€‚ ### 12. ã€æŽ¨è】在并å‘场景下,通过åŒé‡æ£€æŸ¥é”(double-checked locking)实现延迟åˆå§‹åŒ–的优 åŒ–é—®é¢˜éšæ‚£(å¯å‚考 The "Double-Checked Locking is Broken" Declaration),推èè§£ 决方案ä¸è¾ƒä¸ºç®€å•一ç§ï¼ˆé€‚用于 JDK5 åŠä»¥ä¸Šç‰ˆæœ¬ï¼‰ï¼Œå°†ç›®æ ‡å±žæ€§å£°æ˜Žä¸º volatile 型。 å例: ``` java class Singleton { private Helper helper = null; public Helper getHelper() { if (helper == null) synchronized(this) { if (helper == null) helper = new Helper(); } return helper; } // other methods and fields... } ``` ### 13. ã€å‚考】volatile 解决多线程内å˜ä¸å¯è§é—®é¢˜ã€‚对于一写多读,是å¯ä»¥è§£å†³å˜é‡åŒæ¥é—®é¢˜ï¼Œ ä½†æ˜¯å¦‚æžœå¤šå†™ï¼ŒåŒæ ·æ— 法解决线程安全问题。如果是 count++æ“作,使用如下类实现: AtomicInteger count = new AtomicInteger(); count.addAndGet(1); 如果是 JDK8,推 è使用 LongAdder 对象,比 AtomicLong 性能更好(å‡å°‘ä¹è§‚é”çš„é‡è¯•次数)。 ### 14. ã€å‚考】 HashMap 在容é‡ä¸å¤Ÿè¿›è¡Œ resize 时由于高并å‘å¯èƒ½å‡ºçްæ»é“¾ï¼Œå¯¼è‡´ CPU 飙å‡ï¼Œåœ¨ å¼€å‘过程ä¸å¯ä»¥ä½¿ç”¨å…¶å®ƒæ•°æ®ç»“æž„æˆ–åŠ é”æ¥è§„é¿æ¤é£Žé™©ã€‚ ### 15. ã€å‚考】ThreadLocal æ— æ³•è§£å†³å…±äº«å¯¹è±¡çš„æ›´æ–°é—®é¢˜ï¼ŒThreadLocal 对象建议使用 static 修饰。这个å˜é‡æ˜¯é’ˆå¯¹ä¸€ä¸ªçº¿ç¨‹å†…所有æ“ä½œå…±äº«çš„ï¼Œæ‰€ä»¥è®¾ç½®ä¸ºé™æ€å˜é‡ï¼Œæ‰€æœ‰æ¤ç±»å®žä¾‹å…±äº« æ¤é™æ€å˜é‡ ,也就是说在类第一次被使用时装载,åªåˆ†é…一å—å˜å‚¨ç©ºé—´ï¼Œæ‰€æœ‰æ¤ç±»çš„对象(åª è¦æ˜¯è¿™ä¸ªçº¿ç¨‹å†…定义的)都å¯ä»¥æ“控这个å˜é‡ã€‚ ## (七)控制è¯å¥ ### 1. ã€å¼ºåˆ¶ã€‘在一个 switch å—内,æ¯ä¸ª case è¦ä¹ˆé€šè¿‡ break/return ç‰æ¥ç»ˆæ¢ï¼Œè¦ä¹ˆæ³¨é‡Šè¯´æ˜Žç¨‹ åºå°†ç»§ç»æ‰§è¡Œåˆ°å“ªä¸€ä¸ª case 为æ¢ï¼›åœ¨ä¸€ä¸ª switch å—内,都必须包å«ä¸€ä¸ª default è¯å¥å¹¶ä¸” 放在最åŽï¼Œå³ä½¿å®ƒä»€ä¹ˆä»£ç 也没有。 ### 2. ã€å¼ºåˆ¶ã€‘在 if/else/for/while/do è¯å¥ä¸å¿…须使用大括å·ã€‚å³ä½¿åªæœ‰ä¸€è¡Œä»£ç ,é¿å…采用 å•è¡Œçš„ç¼–ç æ–¹å¼ï¼šif (condition) statements; ### 3. ã€æŽ¨è】表达异常的分支时,少用 if-else æ–¹å¼ï¼Œè¿™ç§æ–¹å¼å¯ä»¥æ”¹å†™æˆï¼š ``` java if (condition) { ... return obj; } ``` // 接ç€å†™ else 的业务逻辑代ç ; 说明:如果éžå¾—使用 if()...else if()...else...æ–¹å¼è¡¨è¾¾é€»è¾‘,ã€å¼ºåˆ¶ã€‘é¿å…åŽç»ä»£ç ç»´ 护困难,请勿超过 3 层。 æ£ä¾‹ï¼šè¶…过 3 层的 if-else 的逻辑判æ–代ç å¯ä»¥ä½¿ç”¨å«è¯å¥ã€ç–略模å¼ã€çŠ¶æ€æ¨¡å¼ç‰æ¥å®žçŽ°ï¼Œ å…¶ä¸å«è¯å¥ç¤ºä¾‹å¦‚下: ``` java public void today() { if (isBusy()) { System.out.println(“change time.â€); return; } if (isFree()) { System.out.println(“go to travel.â€); return; } System.out.println(“stay at home to learn Alibaba Java Coding Guidelines.â€); return; } ``` ### 4. ã€æŽ¨è】除常用方法(如 getXxx/isXxx)ç‰å¤–,ä¸è¦åœ¨æ¡ä»¶åˆ¤æ–䏿‰§è¡Œå…¶å®ƒå¤æ‚çš„è¯å¥ï¼Œå°†å¤ æ‚逻辑判æ–的结果赋值给一个有æ„义的布尔å˜é‡å,以æé«˜å¯è¯»æ€§ã€‚ 说明:很多 if è¯å¥å†…çš„é€»è¾‘ç›¸å½“å¤æ‚,阅读者需è¦åˆ†æžæ¡ä»¶è¡¨è¾¾å¼çš„æœ€ç»ˆç»“果,æ‰èƒ½æ˜Žç¡®ä»€ä¹ˆ æ ·çš„æ¡ä»¶æ‰§è¡Œä»€ä¹ˆæ ·çš„è¯å¥ï¼Œé‚£ä¹ˆï¼Œå¦‚果阅读者分æžé€»è¾‘表达å¼é”™è¯¯å‘¢ï¼Ÿ æ£ä¾‹ï¼š // 伪代ç 如下 ``` java final boolean existed = (file.open(fileName, "w") != null) && (...) || (...); if (existed) { ... } ``` å例: ``` java if ((file.open(fileName, "w") != null) && (...) || (...)) { ... } ``` ### 5. ã€æŽ¨è】循环体ä¸çš„è¯å¥è¦è€ƒé‡æ€§èƒ½ï¼Œä»¥ä¸‹æ“作尽é‡ç§»è‡³å¾ªçޝ体外处ç†ï¼Œå¦‚定义对象ã€å˜é‡ã€ èŽ·å–æ•°æ®åº“连接,进行ä¸å¿…è¦çš„ try-catch æ“作(这个 try-catch 是å¦å¯ä»¥ç§»è‡³å¾ªçŽ¯ä½“å¤–ï¼‰ã€‚ ### 6. ã€æŽ¨è】接å£å…¥å‚ä¿æŠ¤ï¼Œè¿™ç§åœºæ™¯å¸¸è§çš„æ˜¯ç”¨äºŽå𿉹釿“作的接å£ã€‚ ### 7. ã€å‚考】下列情形,需è¦è¿›è¡Œå‚æ•°æ ¡éªŒï¼š 1) 调用频次低的方法。 2) æ‰§è¡Œæ—¶é—´å¼€é”€å¾ˆå¤§çš„æ–¹æ³•ã€‚æ¤æƒ…å½¢ä¸ï¼Œå‚æ•°æ ¡éªŒæ—¶é—´å‡ ä¹Žå¯ä»¥å¿½ç•¥ä¸è®¡ï¼Œä½†å¦‚æžœå› ä¸ºå‚ æ•°é”™è¯¯å¯¼è‡´ä¸é—´æ‰§è¡Œå›žé€€ï¼Œæˆ–者错误,那得ä¸å¿å¤±ã€‚ 3) éœ€è¦æžé«˜ç¨³å®šæ€§å’Œå¯ç”¨æ€§çš„æ–¹æ³•。 4) 对外æä¾›çš„开放接å£ï¼Œä¸ç®¡æ˜¯ RPC/API/HTTP 接å£ã€‚ 5) æ•æ„Ÿæƒé™å…¥å£ã€‚ ### 8. ã€å‚考】下列情形,ä¸éœ€è¦è¿›è¡Œå‚æ•°æ ¡éªŒï¼š 1) æžæœ‰å¯èƒ½è¢«å¾ªçŽ¯è°ƒç”¨çš„æ–¹æ³•ã€‚ä½†åœ¨æ–¹æ³•è¯´æ˜Žé‡Œå¿…é¡»æ³¨æ˜Žå¤–éƒ¨å‚æ•°æ£€æŸ¥è¦æ±‚。 2) 底层调用频度比较高的方法。毕竟是åƒçº¯å‡€æ°´è¿‡æ»¤çš„æœ€åŽä¸€é“ï¼Œå‚æ•°é”™è¯¯ä¸å¤ªå¯èƒ½åˆ°åº• 层æ‰ä¼šæš´éœ²é—®é¢˜ã€‚一般 DAO 层与 Service 层都在åŒä¸€ä¸ªåº”用ä¸ï¼Œéƒ¨ç½²åœ¨åŒä¸€å°æœåС噍ä¸ï¼Œæ‰€ 以 DAO çš„å‚æ•°æ ¡éªŒï¼Œå¯ä»¥çœç•¥ã€‚ 3) è¢«å£°æ˜Žæˆ private åªä¼šè¢«è‡ªå·±ä»£ç 所调用的方法,如果能够确定调用方法的代ç ä¼ å…¥å‚ æ•°å·²ç»åšè¿‡æ£€æŸ¥æˆ–者肯定ä¸ä¼šæœ‰é—®é¢˜ï¼Œæ¤æ—¶å¯ä»¥ä¸æ ¡éªŒå‚数。 ## (å…«)注释规约 ### 1. ã€å¼ºåˆ¶ã€‘ç±»ã€ç±»å±žæ€§ã€ç±»æ–¹æ³•的注释必须使用 Javadoc 规范,使用/**内容*/æ ¼å¼ï¼Œä¸å¾—使用 // xxx æ–¹å¼ã€‚ 说明:在 IDE 编辑窗å£ä¸ï¼ŒJavadoc æ–¹å¼ä¼šæç¤ºç›¸å…³æ³¨é‡Šï¼Œç”Ÿæˆ Javadoc å¯ä»¥æ£ç¡®è¾“出相应注 释;在 IDE ä¸ï¼Œå·¥ç¨‹è°ƒç”¨æ–¹æ³•时,ä¸è¿›å…¥æ–¹æ³•å³å¯æ‚¬æµ®æç¤ºæ–¹æ³•ã€å‚æ•°ã€è¿”回值的æ„义,æé«˜ 阅读效率。 ### 2. ã€å¼ºåˆ¶ã€‘所有的抽象方法(包括接å£ä¸çš„æ–¹æ³•)必须è¦ç”¨ Javadoc 注释ã€é™¤äº†è¿”回值ã€å‚数〠异常说明外,还必须指出该方法åšä»€ä¹ˆäº‹æƒ…,实现什么功能。 说明:对åç±»çš„å®žçŽ°è¦æ±‚,或者调用注æ„事项,请一并说明。 ### 3. ã€å¼ºåˆ¶ã€‘æ‰€æœ‰çš„ç±»éƒ½å¿…é¡»æ·»åŠ åˆ›å»ºè€…å’Œåˆ›å»ºæ—¥æœŸã€‚ ### 4. ã€å¼ºåˆ¶ã€‘方法内部å•行注释,在被注释è¯å¥ä¸Šæ–¹å¦èµ·ä¸€è¡Œï¼Œä½¿ç”¨//注释。方法内部多行注释 使用/* */注释,注æ„与代ç 对é½ã€‚ ### 5. ã€å¼ºåˆ¶ã€‘æ‰€æœ‰çš„æžšä¸¾ç±»åž‹å—æ®µå¿…é¡»è¦æœ‰æ³¨é‡Šï¼Œè¯´æ˜Žæ¯ä¸ªæ•°æ®é¡¹çš„用途。 ### 6. ã€æŽ¨è】与其“åŠåŠåâ€è‹±æ–‡æ¥æ³¨é‡Šï¼Œä¸å¦‚ç”¨ä¸æ–‡æ³¨é‡ŠæŠŠé—®é¢˜è¯´æ¸…楚。专有åè¯ä¸Žå…³é”®å—ä¿æŒ 英文原文å³å¯ã€‚ å例:“TCP 连接超时â€è§£é‡Šæˆâ€œä¼ 输控制å议连接超时â€ï¼Œç†è§£å而费脑ç‹ã€‚ ### 7. ã€æŽ¨è】代ç ä¿®æ”¹çš„åŒæ—¶ï¼Œæ³¨é‡Šä¹Ÿè¦è¿›è¡Œç›¸åº”çš„ä¿®æ”¹ï¼Œå°¤å…¶æ˜¯å‚æ•°ã€è¿”回值ã€å¼‚å¸¸ã€æ ¸å¿ƒé€»è¾‘ ç‰çš„修改。 说明:代ç 与注释更新ä¸åŒæ¥ï¼Œå°±åƒè·¯ç½‘与导航软件更新ä¸åŒæ¥ä¸€æ ·ï¼Œå¦‚æžœå¯¼èˆªè½¯ä»¶ä¸¥é‡æ»žåŽï¼Œ 就失去了导航的æ„义。 ### 8. ã€å‚考】谨慎注释掉代ç ã€‚åœ¨ä¸Šæ–¹è¯¦ç»†è¯´æ˜Žï¼Œè€Œä¸æ˜¯ç®€å•åœ°æ³¨é‡ŠæŽ‰ã€‚å¦‚æžœæ— ç”¨ï¼Œåˆ™åˆ é™¤ã€‚ 说明:代ç 被注释掉有两ç§å¯èƒ½æ€§ï¼š1)åŽç»ä¼šæ¢å¤æ¤æ®µä»£ç 逻辑。2)永久ä¸ç”¨ã€‚å‰è€…如果没 有备注信æ¯ï¼Œéš¾ä»¥çŸ¥æ™“注释动机。åŽè€…å»ºè®®ç›´æŽ¥åˆ æŽ‰ï¼ˆä»£ç 仓库ä¿å˜äº†åކå²ä»£ç )。 ### 9. ã€å‚è€ƒã€‘å¯¹äºŽæ³¨é‡Šçš„è¦æ±‚:第一ã€èƒ½å¤Ÿå‡†ç¡®ååº”è®¾è®¡æ€æƒ³å’Œä»£ç 逻辑;第二ã€èƒ½å¤Ÿæè¿°ä¸šåŠ¡å« ä¹‰ï¼Œä½¿åˆ«çš„ç¨‹åºå‘˜èƒ½å¤Ÿè¿…速了解到代ç 背åŽçš„ä¿¡æ¯ã€‚完全没有注释的大段代ç å¯¹äºŽé˜…è¯»è€…å½¢åŒ å¤©ä¹¦ï¼Œæ³¨é‡Šæ˜¯ç»™è‡ªå·±çœ‹çš„ï¼Œå³ä½¿éš”很长时间,也能清晰ç†è§£å½“æ—¶çš„æ€è·¯ï¼›æ³¨é‡Šä¹Ÿæ˜¯ç»™ç»§ä»»è€…看 的,使其能够快速接替自己的工作。 ### 10. ã€å‚考】好的命åã€ä»£ç 结构是自解释的,注释力求精简准确ã€è¡¨è¾¾åˆ°ä½ã€‚é¿å…出现注释的 一个æžç«¯ï¼šè¿‡å¤šè¿‡æ»¥çš„æ³¨é‡Šï¼Œä»£ç 的逻辑一旦修改,修改注释是相当大的负担。 å例: ``` java // put elephant into fridge put(elephant, fridge); ``` 方法å putï¼ŒåŠ ä¸Šä¸¤ä¸ªæœ‰æ„义的å˜é‡å elephant å’Œ fridge,已ç»è¯´æ˜Žäº†è¿™æ˜¯åœ¨å¹²ä»€ä¹ˆï¼Œè¯ 义清晰的代ç ä¸éœ€è¦é¢å¤–的注释。 ### 11. ã€å‚è€ƒã€‘ç‰¹æ®Šæ³¨é‡Šæ ‡è®°ï¼Œè¯·æ³¨æ˜Žæ ‡è®°äººä¸Žæ ‡è®°æ—¶é—´ã€‚æ³¨æ„åŠæ—¶å¤„ç†è¿™äº›æ ‡è®°ï¼Œé€šè¿‡æ ‡è®°æ‰«æï¼Œ ç»å¸¸æ¸…ç†æ¤ç±»æ ‡è®°ã€‚çº¿ä¸Šæ•…éšœæœ‰æ—¶å€™å°±æ˜¯æ¥æºäºŽè¿™äº›æ ‡è®°å¤„的代ç 。 1) 待办事宜(TODO):( æ ‡è®°äººï¼Œæ ‡è®°æ—¶é—´ï¼Œ[é¢„è®¡å¤„ç†æ—¶é—´]) 表示需è¦å®žçŽ°ï¼Œä½†ç›®å‰è¿˜æœªå®žçŽ°çš„åŠŸèƒ½ã€‚è¿™å®žé™…ä¸Šæ˜¯ä¸€ä¸ª Javadoc çš„æ ‡ç¾ï¼Œç›®å‰çš„ Javadoc 还没有实现,但已ç»è¢«å¹¿æ³›ä½¿ç”¨ã€‚åªèƒ½åº”用于类,接å£å’Œæ–¹æ³•ï¼ˆå› ä¸ºå®ƒæ˜¯ä¸€ä¸ª Javadoc æ ‡ç¾ï¼‰ã€‚ 2) 错误,ä¸èƒ½å·¥ä½œï¼ˆFIXME):ï¼ˆæ ‡è®°äººï¼Œæ ‡è®°æ—¶é—´ï¼Œ[é¢„è®¡å¤„ç†æ—¶é—´]) 在注释ä¸ç”¨ FIXME æ ‡è®°æŸä»£ç 是错误的,而且ä¸èƒ½å·¥ä½œï¼Œéœ€è¦åŠæ—¶çº æ£çš„æƒ…况。 ## (ä¹)其它 ### 1. ã€å¼ºåˆ¶ã€‘在使用æ£åˆ™è¡¨è¾¾å¼æ—¶ï¼Œåˆ©ç”¨å¥½å…¶é¢„编译功能,å¯ä»¥æœ‰æ•ˆåŠ å¿«æ£åˆ™åŒ¹é…速度。 说明:ä¸è¦åœ¨æ–¹æ³•体内定义:Pattern pattern = Pattern.compile(规则); ### 2. ã€å¼ºåˆ¶ã€‘velocity 调用 POJO 类的属性时,建议直接使用属性åå–值å³å¯ï¼Œæ¨¡æ¿å¼•擎会自动按 规范调用 POJO çš„ getXxx(),如果是 boolean 基本数æ®ç±»åž‹å˜é‡ï¼ˆboolean 命åä¸éœ€è¦åŠ is å‰ç¼€ï¼‰ï¼Œä¼šè‡ªåŠ¨è°ƒç”¨ isXxx()方法。 说明:注æ„如果是 Boolean 包装类对象,优先调用 getXxx()的方法。 ### 3. ã€å¼ºåˆ¶ã€‘åŽå°è¾“é€ç»™é¡µé¢çš„å˜é‡å¿…é¡»åŠ $!{var}——ä¸é—´çš„æ„Ÿå¹å·ã€‚ 说明:如果 var=null 或者ä¸å˜åœ¨ï¼Œé‚£ä¹ˆ${var}会直接显示在页é¢ä¸Šã€‚ ### 4. ã€å¼ºåˆ¶ã€‘æ³¨æ„ Math.random() 这个方法返回是 double 类型,注æ„å–值的范围 0≤x<1(能够 å–到零值,注æ„é™¤é›¶å¼‚å¸¸ï¼‰ï¼Œå¦‚æžœæƒ³èŽ·å–æ•´æ•°ç±»åž‹çš„éšæœºæ•°ï¼Œä¸è¦å°† x 放大 10 的若干å€ç„¶åŽ å–æ•´ï¼Œç›´æŽ¥ä½¿ç”¨ Random 对象的 nextInt 或者 nextLong 方法。 ### 5. ã€å¼ºåˆ¶ã€‘获å–当剿¯«ç§’æ•° System.currentTimeMillis(); è€Œä¸æ˜¯ new Date().getTime(); è¯´æ˜Žï¼šå¦‚æžœæƒ³èŽ·å–æ›´åŠ ç²¾ç¡®çš„çº³ç§’çº§æ—¶é—´å€¼ï¼Œä½¿ç”¨ System.nanoTime()的方å¼ã€‚在 JDK8 ä¸ï¼Œ 针对统计时间ç‰åœºæ™¯ï¼ŒæŽ¨è使用 Instant 类。 ### 6. ã€æŽ¨è】ä¸è¦åœ¨è§†å›¾æ¨¡æ¿ä¸åР入任何夿‚的逻辑。 è¯´æ˜Žï¼šæ ¹æ® MVC ç†è®ºï¼Œè§†å›¾çš„èŒè´£æ˜¯å±•示,ä¸è¦æŠ¢æ¨¡åž‹å’ŒæŽ§åˆ¶å™¨çš„æ´»ã€‚ ### 7. ã€æŽ¨è】任何数æ®ç»“æž„çš„æž„é€ æˆ–åˆå§‹åŒ–,都应指定大å°ï¼Œé¿å…æ•°æ®ç»“æž„æ— é™å¢žé•¿åƒå…‰å†…å˜ã€‚ ### 8. ã€æŽ¨èã€‘åŠæ—¶æ¸…ç†ä¸å†ä½¿ç”¨çš„ä»£ç æ®µæˆ–é…置信æ¯ã€‚ è¯´æ˜Žï¼šå¯¹äºŽåžƒåœ¾ä»£ç æˆ–过时é…置,åšå†³æ¸…ç†å¹²å‡€ï¼Œé¿å…程åºè¿‡åº¦è‡ƒè‚¿ï¼Œä»£ç 冗余。 æ£ä¾‹ï¼šå¯¹äºŽæš‚时被注释掉,åŽç»å¯èƒ½æ¢å¤ä½¿ç”¨çš„代ç 片æ–,在注释代ç 上方,统一规定使用三 个斜æ (///)æ¥è¯´æ˜Žæ³¨é‡ŠæŽ‰ä»£ç çš„ç†ç”±ã€‚ # 二ã€å¼‚常日志 ## (一)å¼‚å¸¸å¤„ç† ### 1. ã€å¼ºåˆ¶ã€‘Java 类库ä¸å®šä¹‰çš„一类 RuntimeException å¯ä»¥é€šè¿‡é¢„先检查进行规é¿ï¼Œè€Œä¸åº”该 通过 catch æ¥å¤„ç†ï¼Œæ¯”如:IndexOutOfBoundsException,NullPointerException ç‰ç‰ã€‚ è¯´æ˜Žï¼šæ— æ³•é€šè¿‡é¢„æ£€æŸ¥çš„å¼‚å¸¸é™¤å¤–ï¼Œå¦‚åœ¨è§£æžä¸€ä¸ªå¤–éƒ¨ä¼ æ¥çš„å—ç¬¦ä¸²å½¢å¼æ•°å—时,通过 catch NumberFormatException æ¥å®žçŽ°ã€‚ æ£ä¾‹ï¼š ``` java if (obj != null) { ... } ``` å例 ``` java try { obj.method() } catch (NullPointerException e) { ... } ``` ### 2. ã€å¼ºåˆ¶ã€‘异常ä¸è¦ç”¨æ¥åšæµç¨‹æŽ§åˆ¶ï¼Œæ¡ä»¶æŽ§åˆ¶ï¼Œå› ä¸ºå¼‚å¸¸çš„å¤„ç†æ•ˆçŽ‡æ¯”æ¡ä»¶åˆ†æ”¯ä½Žã€‚ ### 3. ã€å¼ºåˆ¶ã€‘对大段代ç 进行 try-catch,这是ä¸è´Ÿè´£ä»»çš„表现。catch 时请分清稳定代ç å’Œéžç¨³ 定代ç ï¼Œç¨³å®šä»£ç æŒ‡çš„æ˜¯æ— 论如何ä¸ä¼šå‡ºé”™çš„代ç 。对于éžç¨³å®šä»£ç çš„ catch å°½å¯èƒ½è¿›è¡ŒåŒºåˆ† 异常类型,å†åšå¯¹åº”的异常处ç†ã€‚ ### 4. ã€å¼ºåˆ¶ã€‘æ•获异常是为了处ç†å®ƒï¼Œä¸è¦æ•获了å´ä»€ä¹ˆéƒ½ä¸å¤„ç†è€ŒæŠ›å¼ƒä¹‹ï¼Œå¦‚æžœä¸æƒ³å¤„ç†å®ƒï¼Œè¯· 将该异常抛给它的调用者。最外层的业务使用者,必须处ç†å¼‚常,将其转化为用户å¯ä»¥ç†è§£çš„ 内容。 ### 5. ã€å¼ºåˆ¶ã€‘有 try å—æ”¾åˆ°äº†äº‹åС代ç ä¸ï¼Œcatch 异常åŽï¼Œå¦‚果需è¦å›žæ»šäº‹åŠ¡ï¼Œä¸€å®šè¦æ³¨æ„手动回 滚事务。 ### 6. ã€å¼ºåˆ¶ã€‘finally å—必须对资æºå¯¹è±¡ã€æµå¯¹è±¡è¿›è¡Œå…³é—,有异常也è¦åš try-catch。 说明:如果 JDK7 åŠä»¥ä¸Šï¼Œå¯ä»¥ä½¿ç”¨ try-with-resources æ–¹å¼ã€‚ ### 7. ã€å¼ºåˆ¶ã€‘ä¸èƒ½åœ¨ finally å—ä¸ä½¿ç”¨ return,finally å—ä¸çš„ return è¿”å›žåŽæ–¹æ³•ç»“æŸæ‰§è¡Œï¼Œä¸ ä¼šå†æ‰§è¡Œ try å—ä¸çš„ return è¯å¥ã€‚ ### 8. ã€å¼ºåˆ¶ã€‘æ•获异常与抛异常,必须是完全匹é…,或者æ•获异常是抛异常的父类。 说明:如果预期对方抛的是绣çƒï¼Œå®žé™…接到的是铅çƒï¼Œå°±ä¼šäº§ç”Ÿæ„外情况。 ### 9. ã€æŽ¨è】方法的返回值å¯ä»¥ä¸º null,ä¸å¼ºåˆ¶è¿”回空集åˆï¼Œæˆ–者空对象ç‰ï¼Œå¿…é¡»æ·»åŠ æ³¨é‡Šå……åˆ† 说明什么情况下会返回 null 值。调用方需è¦è¿›è¡Œ null 判æ–é˜²æ¢ NPE 问题。 è¯´æ˜Žï¼šæœ¬æ‰‹å†Œæ˜Žç¡®é˜²æ¢ NPE 是调用者的责任。å³ä½¿è¢«è°ƒç”¨æ–¹æ³•è¿”å›žç©ºé›†åˆæˆ–者空对象,对调用 者æ¥è¯´ï¼Œä¹Ÿå¹¶éžé«˜æž•æ— å¿§ï¼Œå¿…é¡»è€ƒè™‘åˆ°è¿œç¨‹è°ƒç”¨å¤±è´¥ã€åºåˆ—化失败ã€è¿è¡Œæ—¶å¼‚常ç‰åœºæ™¯è¿”回 null 的情况。 ### 10. ã€æŽ¨èã€‘é˜²æ¢ NPE,是程åºå‘˜çš„åŸºæœ¬ä¿®å…»ï¼Œæ³¨æ„ NPE 产生的场景: 1)返回类型为基本数æ®ç±»åž‹ï¼Œreturn 包装数æ®ç±»åž‹çš„对象时,自动拆箱有å¯èƒ½äº§ç”Ÿ NPE。 å例: ``` java public int f() { return Integer对象 } ``` 如果为 null,自动解箱抛 NPE。 2) æ•°æ®åº“的查询结果å¯èƒ½ä¸º null。 3) 集åˆé‡Œçš„å…ƒç´ å³ä½¿ isNotEmpty,å–出的数æ®å…ƒç´ 也å¯èƒ½ä¸º null。 4) è¿œç¨‹è°ƒç”¨è¿”å›žå¯¹è±¡æ—¶ï¼Œä¸€å¾‹è¦æ±‚进行空指针判æ–ï¼Œé˜²æ¢ NPE。 5) 对于 Session ä¸èŽ·å–的数æ®ï¼Œå»ºè®® NPE 检查,é¿å…空指针。 6) 级è”调用 obj.getA().getB().getC();一连串调用,易产生 NPE。 æ£ä¾‹ï¼šä½¿ç”¨ JDK8 çš„ Optional ç±»æ¥é˜²æ¢ NPE 问题。 ### 11. ã€æŽ¨è】定义时区分 unchecked / checked 异常,é¿å…直接抛出 new RuntimeException(), æ›´ä¸å…许抛出 Exception 或者 Throwable,应使用有业务å«ä¹‰çš„自定义异常。推è业界已定义 过的自定义异常,如:DAOException / ServiceException ç‰ã€‚ ### 12. ã€å‚考】在代ç ä¸ä½¿ç”¨â€œæŠ›å¼‚常â€è¿˜æ˜¯â€œè¿”回错误ç â€ï¼Œå¯¹äºŽå…¬å¸å¤–çš„ http/api 开放接å£å¿…é¡» 使用“错误ç â€ï¼›è€Œåº”用内部推è异常抛出;跨应用间 RPC 调用优先考虑使用 Result æ–¹å¼ï¼Œå° 装 isSuccess()方法ã€â€œé”™è¯¯ç â€ã€â€œé”™è¯¯ç®€çŸä¿¡æ¯â€ã€‚ 说明:关于 RPC 方法返回方å¼ä½¿ç”¨ Result æ–¹å¼çš„ç†ç”±ï¼š 1)使用抛异常返回方å¼ï¼Œè°ƒç”¨æ–¹å¦‚果没有æ•获到就会产生è¿è¡Œæ—¶é”™è¯¯ã€‚ 2)如果ä¸åŠ æ ˆä¿¡æ¯ï¼Œåªæ˜¯ new è‡ªå®šä¹‰å¼‚å¸¸ï¼ŒåŠ å…¥è‡ªå·±çš„ç†è§£çš„ error message,对于调用 端解决问题的帮助ä¸ä¼šå¤ªå¤šã€‚å¦‚æžœåŠ äº†æ ˆä¿¡æ¯ï¼Œåœ¨é¢‘ç¹è°ƒç”¨å‡ºé”™çš„æƒ…况下,数æ®åºåˆ—åŒ–å’Œä¼ è¾“ 的性能æŸè€—也是问题。 ### 13. ã€å‚考】é¿å…出现é‡å¤çš„代ç (Don’t Repeat Yourselfï¼‰ï¼Œå³ DRY 原则。 è¯´æ˜Žï¼šéšæ„å¤åˆ¶å’Œç²˜è´´ä»£ç ,必然会导致代ç çš„é‡å¤ï¼Œåœ¨ä»¥åŽéœ€è¦ä¿®æ”¹æ—¶ï¼Œéœ€è¦ä¿®æ”¹æ‰€æœ‰çš„副 æœ¬ï¼Œå®¹æ˜“é—æ¼ã€‚å¿…è¦æ—¶æŠ½å–共性方法,或者抽象公共类,甚至是组件化。 æ£ä¾‹ï¼šä¸€ä¸ªç±»ä¸æœ‰å¤šä¸ª public 方法,都需è¦è¿›è¡Œæ•°è¡Œç›¸åŒçš„傿•°æ ¡éªŒæ“作,这个时候请抽å–: ``` java private boolean checkParam(DTO dto) { ... } ``` ## (二)日志规约 ### 1. ã€å¼ºåˆ¶ã€‘应用ä¸ä¸å¯ç›´æŽ¥ä½¿ç”¨æ—¥å¿—系统(Log4jã€Logback)ä¸çš„ API,而应ä¾èµ–使用日志框架 SLF4J ä¸çš„ APIï¼Œä½¿ç”¨é—¨é¢æ¨¡å¼çš„æ—¥å¿—框架,有利于维护和å„ä¸ªç±»çš„æ—¥å¿—å¤„ç†æ–¹å¼ç»Ÿä¸€ã€‚ ``` java import org.slf4j.Logger; import org.slf4j.LoggerFactory; private static final Logger logger = LoggerFactory.getLogger(Abc.class); ``` ### 2. ã€å¼ºåˆ¶ã€‘日志文件推è至少ä¿å˜ 15 å¤©ï¼Œå› ä¸ºæœ‰äº›å¼‚å¸¸å…·å¤‡ä»¥â€œå‘¨â€ä¸ºé¢‘次å‘生的特点。 ### 3. ã€å¼ºåˆ¶ã€‘应用ä¸çš„æ‰©å±•日志(如打点ã€ä¸´æ—¶ç›‘控ã€è®¿é—®æ—¥å¿—ç‰ï¼‰å‘½åæ–¹å¼ï¼š appName_logType_logName.log。logType:日志类型,推è分类有 stats/desc/monitor/visit ç‰ï¼›logName:日志æè¿°ã€‚è¿™ç§å‘½å的好处:通过文件åå°±å¯çŸ¥ 铿—¥å¿—文件属于什么应用,什么类型,什么目的,也有利于归类查找。 æ£ä¾‹ï¼šmppserver 应用ä¸å•独监控时区转æ¢å¼‚常,如: mppserver_monitor_timeZoneConvert.log 说明:推èå¯¹æ—¥å¿—è¿›è¡Œåˆ†ç±»ï¼Œå¦‚å°†é”™è¯¯æ—¥å¿—å’Œä¸šåŠ¡æ—¥å¿—åˆ†å¼€å˜æ”¾ï¼Œä¾¿äºŽå¼€å‘人员查看,也便于 é€šè¿‡æ—¥å¿—å¯¹ç³»ç»Ÿè¿›è¡ŒåŠæ—¶ç›‘控。 ### 4. ã€å¼ºåˆ¶ã€‘对 trace/debug/info 级别的日志输出,必须使用æ¡ä»¶è¾“å‡ºå½¢å¼æˆ–者使用å ä½ç¬¦çš„æ–¹ å¼ã€‚ 说明:logger.debug("Processing trade with id: " + id + " and symbol: " + symbol); 如果日志级别是 warn,上述日志ä¸ä¼šæ‰“å°ï¼Œä½†æ˜¯ä¼šæ‰§è¡Œå—符串拼接æ“作,如果 symbol 是对象, 会执行 toString()方法,浪费了系统资æºï¼Œæ‰§è¡Œäº†ä¸Šè¿°æ“ä½œï¼Œæœ€ç»ˆæ—¥å¿—å´æ²¡æœ‰æ‰“å°ã€‚ æ£ä¾‹ï¼šï¼ˆæ¡ä»¶ï¼‰ ``` java if (logger.isDebugEnabled()) { logger.debug("Processing trade with id: " + id + " and symbol: " + symbol); } ``` æ£ä¾‹ï¼šï¼ˆå ä½ç¬¦ï¼‰ ``` java logger.debug("Processing trade with id: {} and symbol : {} ", id, symbol); ``` ### 5. ã€å¼ºåˆ¶ã€‘é¿å…é‡å¤æ‰“å°æ—¥å¿—,浪费ç£ç›˜ç©ºé—´ï¼ŒåŠ¡å¿…åœ¨ log4j.xml ä¸è®¾ç½® additivity=false。 æ£ä¾‹ï¼š\<logger name="com.taobao.dubbo.config" additivity="false"> ### 6. ã€å¼ºåˆ¶ã€‘异常信æ¯åº”该包括两类信æ¯ï¼šæ¡ˆå‘现场信æ¯å’Œå¼‚å¸¸å †æ ˆä¿¡æ¯ã€‚如果ä¸å¤„ç†ï¼Œé‚£ä¹ˆé€šè¿‡ å…³é”®å— throws 往上抛出。 æ£ä¾‹ï¼šlogger.error(å„ç±»å‚æ•°æˆ–者对象 toString + "_" + e.getMessage(), e); ### 7. ã€æŽ¨èã€‘è°¨æ…Žåœ°è®°å½•æ—¥å¿—ã€‚ç”Ÿäº§çŽ¯å¢ƒç¦æ¢è¾“出 debug 日志;有选择地输出 info 日志;如果使 用 warn æ¥è®°å½•刚上线时的业务行为信æ¯ï¼Œä¸€å®šè¦æ³¨æ„日志输出é‡çš„问题,é¿å…把æœåС噍ç£ç›˜ æ’‘çˆ†ï¼Œå¹¶è®°å¾—åŠæ—¶åˆ 除这些观察日志。 说明:大é‡åœ°è¾“å‡ºæ— æ•ˆæ—¥å¿—ï¼Œä¸åˆ©äºŽç³»ç»Ÿæ€§èƒ½æå‡ï¼Œä¹Ÿä¸åˆ©äºŽå¿«é€Ÿå®šä½é”™è¯¯ç‚¹ã€‚记录日志时请 æ€è€ƒï¼šè¿™äº›æ—¥å¿—真的有人看å—ï¼Ÿçœ‹åˆ°è¿™æ¡æ—¥å¿—ä½ èƒ½åšä»€ä¹ˆï¼Ÿèƒ½ä¸èƒ½ç»™é—®é¢˜æŽ’查带æ¥å¥½å¤„? ### 8. ã€å‚考】å¯ä»¥ä½¿ç”¨ warn 日志级别æ¥è®°å½•ç”¨æˆ·è¾“å…¥å‚æ•°é”™è¯¯çš„æƒ…况,é¿å…ç”¨æˆ·æŠ•è¯‰æ—¶ï¼Œæ— æ‰€é€‚ ä»Žã€‚æ³¨æ„æ—¥å¿—输出的级别,error 级别åªè®°å½•系统逻辑出错ã€å¼‚常ç‰é‡è¦çš„错误信æ¯ã€‚如éžå¿… è¦ï¼Œè¯·ä¸è¦åœ¨æ¤åœºæ™¯æ‰“出 error 级别。 # 三ã€å•元测试 ### 1. ã€å¼ºåˆ¶ã€‘好的å•元测试必须éµå®ˆ AIR 原则。 说明:å•元测试在线上è¿è¡Œæ—¶ï¼Œæ„Ÿè§‰åƒç©ºæ°”(AIRï¼‰ä¸€æ ·å¹¶ä¸å˜åœ¨ï¼Œä½†åœ¨æµ‹è¯•è´¨é‡çš„ä¿éšœä¸Šï¼Œ å´æ˜¯éžå¸¸å…³é”®çš„。好的å•元测试å®è§‚上æ¥è¯´ï¼Œå…·æœ‰è‡ªåŠ¨åŒ–ã€ç‹¬ç«‹æ€§ã€å¯é‡å¤æ‰§è¡Œçš„特点。 - A:Automatic(自动化) - I:Independent(独立性) - R:Repeatable(å¯é‡å¤ï¼‰ ### 2. ã€å¼ºåˆ¶ã€‘å•元测试应该是全自动执行的,并且éžäº¤äº’å¼çš„。测试框架通常是定期执行的,执行 è¿‡ç¨‹å¿…é¡»å®Œå…¨è‡ªåŠ¨åŒ–æ‰æœ‰æ„义。输出结果需è¦äººå·¥æ£€æŸ¥çš„æµ‹è¯•䏿˜¯ä¸€ä¸ªå¥½çš„å•元测试。å•元测 试ä¸ä¸å‡†ä½¿ç”¨ System.out æ¥è¿›è¡Œäººè‚‰éªŒè¯ï¼Œå¿…须使用 assert æ¥éªŒè¯ã€‚ ### 3. ã€å¼ºåˆ¶ã€‘ä¿æŒå•元测试的独立性。为了ä¿è¯å•元测试稳定å¯é 且便于维护,å•元测试用例之间 决ä¸èƒ½äº’相调用,也ä¸èƒ½ä¾èµ–æ‰§è¡Œçš„å…ˆåŽæ¬¡åºã€‚ å例:method2 需è¦ä¾èµ– method1 的执行,将执行结果åšä¸º method2 的输入。 ### 4. ã€å¼ºåˆ¶ã€‘å•元测试是å¯ä»¥é‡å¤æ‰§è¡Œçš„,ä¸èƒ½å—到外界环境的影å“。 说明:å•元测试通常会被放到æŒç»é›†æˆä¸ï¼Œæ¯æ¬¡æœ‰ä»£ç check in æ—¶å•元测试都会被执行。如 æžœå•æµ‹å¯¹å¤–éƒ¨çŽ¯å¢ƒï¼ˆç½‘ç»œã€æœåŠ¡ã€ä¸é—´ä»¶ç‰ï¼‰æœ‰ä¾èµ–,容易导致æŒç»é›†æˆæœºåˆ¶çš„ä¸å¯ç”¨ã€‚ æ£ä¾‹ï¼šä¸ºäº†ä¸å—外界环境影å“ï¼Œè¦æ±‚è®¾è®¡ä»£ç æ—¶å°±æŠŠ SUT çš„ä¾èµ–æ”¹æˆæ³¨å…¥ï¼Œåœ¨æµ‹è¯•时用 spring è¿™æ ·çš„ DI 框架注入一个本地(内å˜ï¼‰å®žçŽ°æˆ–è€… Mock 实现。 ### 5. ã€å¼ºåˆ¶ã€‘对于å•元测试,è¦ä¿è¯æµ‹è¯•粒度足够å°ï¼Œæœ‰åŠ©äºŽç²¾ç¡®å®šä½é—®é¢˜ã€‚啿µ‹ç²’度至多是类级 别,一般是方法级别。 è¯´æ˜Žï¼šåªæœ‰æµ‹è¯•ç²’åº¦å°æ‰èƒ½åœ¨å‡ºé”™æ—¶å°½å¿«å®šä½åˆ°å‡ºé”™ä½ç½®ã€‚啿µ‹ä¸è´Ÿè´£æ£€æŸ¥è·¨ç±»æˆ–者跨系统的 äº¤äº’é€»è¾‘ï¼Œé‚£æ˜¯é›†æˆæµ‹è¯•的领域。 ### 6. ã€å¼ºåˆ¶ã€‘æ ¸å¿ƒä¸šåŠ¡ã€æ ¸å¿ƒåº”ç”¨ã€æ ¸å¿ƒæ¨¡å—的增é‡ä»£ç ç¡®ä¿å•元测试通过。 说明:新增代ç åŠæ—¶è¡¥å……å•元测试,如果新增代ç å½±å“了原有å•å…ƒæµ‹è¯•ï¼Œè¯·åŠæ—¶ä¿®æ£ã€‚ ### 7. ã€å¼ºåˆ¶ã€‘å•元测试代ç 必须写在如下工程目录:src/test/java,ä¸å…许写在业务代ç 目录下。 说明:æºç 构建时会跳过æ¤ç›®å½•,而å•å…ƒæµ‹è¯•æ¡†æž¶é»˜è®¤æ˜¯æ‰«ææ¤ç›®å½•ã€‚ ### 8. ã€æŽ¨è】å•å…ƒæµ‹è¯•çš„åŸºæœ¬ç›®æ ‡ï¼šè¯å¥è¦†ç›–率达到 70%ï¼›æ ¸å¿ƒæ¨¡å—çš„è¯å¥è¦†ç›–率和分支覆盖率都 è¦è¾¾åˆ° 100% è¯´æ˜Žï¼šåœ¨å·¥ç¨‹è§„çº¦çš„åº”ç”¨åˆ†å±‚ä¸æåˆ°çš„ DAO 层,Manager 层,å¯é‡ç”¨åº¦é«˜çš„ Service,都应该 进行å•元测试。 ### 9. ã€æŽ¨è】编写å•元测试代ç éµå®ˆ BCDE 原则,以ä¿è¯è¢«æµ‹è¯•模å—的交付质é‡ã€‚ - B:Border,边界值测试,包括循环边界ã€ç‰¹æ®Šå–值ã€ç‰¹æ®Šæ—¶é—´ç‚¹ã€æ•°æ®é¡ºåºç‰ã€‚ - C:Correct,æ£ç¡®çš„输入,并得到预期的结果。 - D:Design,与设计文档相结åˆï¼Œæ¥ç¼–写å•元测试。 - E:Error,强制错误信æ¯è¾“å…¥ï¼ˆå¦‚ï¼šéžæ³•æ•°æ®ã€å¼‚常æµç¨‹ã€éžä¸šåŠ¡å…许输入ç‰ï¼‰ï¼Œå¹¶å¾— 到预期的结果。 ### 10. ã€æŽ¨è】对于数æ®åº“ç›¸å…³çš„æŸ¥è¯¢ï¼Œæ›´æ–°ï¼Œåˆ é™¤ç‰æ“作,ä¸èƒ½å‡è®¾æ•°æ®åº“é‡Œçš„æ•°æ®æ˜¯å˜åœ¨çš„, 或者直接æ“作数æ®åº“æŠŠæ•°æ®æ’å…¥è¿›åŽ»ï¼Œè¯·ä½¿ç”¨ç¨‹åºæ’入或者导入数æ®çš„æ–¹å¼æ¥å‡†å¤‡æ•°æ®ã€‚ åä¾‹ï¼šåˆ é™¤æŸä¸€è¡Œæ•°æ®çš„å•元测试,在数æ®åº“ä¸ï¼Œå…ˆç›´æŽ¥æ‰‹åŠ¨å¢žåŠ ä¸€è¡Œä½œä¸ºåˆ é™¤ç›®æ ‡ï¼Œä½†æ˜¯è¿™ 一行新增数æ®å¹¶ä¸ç¬¦åˆä¸šåŠ¡æ’入规则,导致测试结果异常。 ### 11. ã€æŽ¨è】和数æ®åº“相关的å•元测试,å¯ä»¥è®¾å®šè‡ªåŠ¨å›žæ»šæœºåˆ¶ï¼Œä¸ç»™æ•°æ®åº“é€ æˆè„æ•°æ®ã€‚或者 对å•å…ƒæµ‹è¯•äº§ç”Ÿçš„æ•°æ®æœ‰æ˜Žç¡®çš„å‰åŽç¼€æ ‡è¯†ã€‚ æ£ä¾‹ï¼šåœ¨ RDC 内部å•元测试ä¸ï¼Œä½¿ç”¨ RDC_UNIT_TEST_çš„å‰ç¼€æ ‡è¯†æ•°æ®ã€‚ ### 12. ã€æŽ¨è】对于ä¸å¯æµ‹çš„代ç 建议åšå¿…è¦çš„釿ž„,使代ç å˜å¾—坿µ‹ï¼Œé¿å…ä¸ºäº†è¾¾åˆ°æµ‹è¯•è¦æ±‚而 书写ä¸è§„范测试代ç 。 ### 13. ã€æŽ¨è】在设计评审阶段,开å‘人员需è¦å’Œæµ‹è¯•人员一起确定å•元测试范围,å•元测试最好 覆盖所有测试用例(UC)。 ### 14. ã€æŽ¨è】å•元测试作为一ç§è´¨é‡ä¿éšœæ‰‹æ®µï¼Œä¸å»ºè®®é¡¹ç›®å‘布åŽè¡¥å……å•元测试用例,建议在项 ç›®ææµ‹å‰å®Œæˆå•元测试。 ### 15. ã€å‚考】为了更方便地进行å•元测试,业务代ç 应é¿å…以下情况: - æž„é€ æ–¹æ³•ä¸åšçš„事情过多。 - å˜åœ¨è¿‡å¤šçš„全局å˜é‡å’Œé™æ€æ–¹æ³•。 - å˜åœ¨è¿‡å¤šçš„外部ä¾èµ–。 - å˜åœ¨è¿‡å¤šçš„æ¡ä»¶è¯å¥ã€‚ 说明:多层æ¡ä»¶è¯å¥å»ºè®®ä½¿ç”¨å«è¯å¥ã€ç–略模å¼ã€çŠ¶æ€æ¨¡å¼ç‰æ–¹å¼é‡æž„。 ### 16. ã€å‚考】ä¸è¦å¯¹å•元测试å˜åœ¨å¦‚下误解: - 那是测试åŒå¦å¹²çš„äº‹æƒ…ã€‚æœ¬æ–‡æ˜¯å¼€å‘æ‰‹å†Œï¼Œå‡¡æ˜¯æœ¬æ–‡å†…容都是与开å‘åŒå¦å¼ºç›¸å…³çš„。 - å•å…ƒæµ‹è¯•ä»£ç æ˜¯å¤šä½™çš„。汽车的整体功能与å„å•元部件的测试æ£å¸¸ä¸Žå¦æ˜¯å¼ºç›¸å…³çš„。 - å•元测试代ç ä¸éœ€è¦ç»´æŠ¤ã€‚一年åŠè½½åŽï¼Œé‚£ä¹ˆå•å…ƒæµ‹è¯•å‡ ä¹Žå¤„äºŽåºŸå¼ƒçŠ¶æ€ã€‚ - å•元测试与线上故障没有辩è¯å…³ç³»ã€‚好的å•元测试能够最大é™åº¦åœ°è§„é¿çº¿ä¸Šæ•…障。 # å››ã€å®‰å…¨è§„约 ### 1. ã€å¼ºåˆ¶ã€‘éš¶å±žäºŽç”¨æˆ·ä¸ªäººçš„é¡µé¢æˆ–者功能必须进行æƒé™æŽ§åˆ¶æ ¡éªŒã€‚ è¯´æ˜Žï¼šé˜²æ¢æ²¡æœ‰åšæ°´å¹³æƒé™æ ¡éªŒå°±å¯éšæ„访问ã€ä¿®æ”¹ã€åˆ 除别人的数æ®ï¼Œæ¯”如查看他人的ç§ä¿¡ 内容ã€ä¿®æ”¹ä»–人的订å•。 ### 2. ã€å¼ºåˆ¶ã€‘ç”¨æˆ·æ•æ„Ÿæ•°æ®ç¦æ¢ç›´æŽ¥å±•示,必须对展示数æ®è¿›è¡Œè„±æ•。 说明:查看个人手机å·ç 会显示æˆ:158****9119,éšè—ä¸é—´ 4 ä½ï¼Œé˜²æ¢éšç§æ³„露。 ### 3. ã€å¼ºåˆ¶ã€‘用户输入的 SQL 傿•°ä¸¥æ ¼ä½¿ç”¨å‚数绑定或者 METADATA å—æ®µå€¼é™å®šï¼Œé˜²æ¢ SQL 注入, ç¦æ¢å—符串拼接 SQL 访问数æ®åº“。 ### 4. ã€å¼ºåˆ¶ã€‘ç”¨æˆ·è¯·æ±‚ä¼ å…¥çš„ä»»ä½•å‚æ•°å¿…é¡»åšæœ‰æ•ˆæ€§éªŒè¯ã€‚ è¯´æ˜Žï¼šå¿½ç•¥å‚æ•°æ ¡éªŒå¯èƒ½å¯¼è‡´ï¼š - page size è¿‡å¤§å¯¼è‡´å†…å˜æº¢å‡º - æ¶æ„ order by 导致数æ®åº“慢查询 - ä»»æ„é‡å®šå‘ - SQL 注入 - ååºåˆ—化注入 - æ£åˆ™è¾“å…¥æºä¸²æ‹’ç»æœåŠ¡ ReDoS 说明:Java 代ç 用æ£åˆ™æ¥éªŒè¯å®¢æˆ·ç«¯çš„输入,有些æ£åˆ™å†™æ³•éªŒè¯æ™®é€šç”¨æˆ·è¾“入没有问题, ä½†æ˜¯å¦‚æžœæ”»å‡»äººå‘˜ä½¿ç”¨çš„æ˜¯ç‰¹æ®Šæž„é€ çš„å—符串æ¥éªŒè¯ï¼Œæœ‰å¯èƒ½å¯¼è‡´æ»å¾ªçŽ¯çš„ç»“æžœã€‚ ### 5. ã€å¼ºåˆ¶ã€‘ç¦æ¢å‘ HTML 页é¢è¾“出未ç»å®‰å…¨è¿‡æ»¤æˆ–未æ£ç¡®è½¬ä¹‰çš„用户数æ®ã€‚ ### 6. ã€å¼ºåˆ¶ã€‘表å•ã€AJAX æäº¤å¿…须执行 CSRF 安全过滤。 说明:CSRF(Cross-site request forgery)è·¨ç«™è¯·æ±‚ä¼ªé€ æ˜¯ä¸€ç±»å¸¸è§ç¼–ç¨‹æ¼æ´žã€‚对于å˜åœ¨ CSRF æ¼æ´žçš„应用/网站,攻击者å¯ä»¥äº‹å…ˆæž„é€ å¥½ URL,åªè¦å—害者用户一访问,åŽå°ä¾¿åœ¨ç”¨æˆ· ä¸çŸ¥æƒ…情况下对数æ®åº“ä¸ç”¨æˆ·å‚数进行相应修改。 ### 7. ã€å¼ºåˆ¶ã€‘在使用平å°èµ„æºï¼Œè¬å¦‚çŸä¿¡ã€é‚®ä»¶ã€ç”µè¯ã€ä¸‹å•ã€æ”¯ä»˜ï¼Œå¿…须实现æ£ç¡®çš„é˜²é‡æ”¾é™åˆ¶ï¼Œ 如数é‡é™åˆ¶ã€ç–²åŠ³åº¦æŽ§åˆ¶ã€éªŒè¯ç æ ¡éªŒï¼Œé¿å…被滥刷ã€èµ„æŸã€‚ 说明:如注册时å‘é€éªŒè¯ç 到手机,如果没有é™åˆ¶æ¬¡æ•°å’Œé¢‘率,那么å¯ä»¥åˆ©ç”¨æ¤åŠŸèƒ½éªšæ‰°åˆ°å…¶ å®ƒç”¨æˆ·ï¼Œå¹¶é€ æˆçŸä¿¡å¹³å°èµ„æºæµªè´¹ã€‚ ### 8. ã€æŽ¨è】å‘è´´ã€è¯„论ã€å‘é€å³æ—¶æ¶ˆæ¯ç‰ç”¨æˆ·ç”Ÿæˆå†…å®¹çš„åœºæ™¯å¿…é¡»å®žçŽ°é˜²åˆ·ã€æ–‡æœ¬å†…容è¿ç¦è¯è¿‡ 滤ç‰é£ŽæŽ§ç–略。 # 五ã€MySQL æ•°æ®åº“ ## (一)建表规约 ### 1. ã€å¼ºåˆ¶ã€‘è¡¨è¾¾æ˜¯ä¸Žå¦æ¦‚å¿µçš„å—æ®µï¼Œå¿…须使用 is_xxx 的方å¼å‘½å,数æ®ç±»åž‹æ˜¯ unsigned tinyint ( 1 表示是,0 表示å¦ï¼‰ã€‚ è¯´æ˜Žï¼šä»»ä½•å—æ®µå¦‚果为éžè´Ÿæ•°ï¼Œå¿…须是 unsigned。 æ£ä¾‹ï¼šè¡¨è¾¾é€»è¾‘åˆ é™¤çš„å—æ®µå is_deleted,1 è¡¨ç¤ºåˆ é™¤ï¼Œ0 è¡¨ç¤ºæœªåˆ é™¤ã€‚ ### 2. ã€å¼ºåˆ¶ã€‘表åã€å—段å必须使用å°å†™å—æ¯æˆ–æ•°å—ï¼Œç¦æ¢å‡ºçŽ°æ•°å—å¼€å¤´ï¼Œç¦æ¢ä¸¤ä¸ªä¸‹åˆ’线ä¸é—´åª 出现数å—。数æ®åº“å—æ®µåçš„ä¿®æ”¹ä»£ä»·å¾ˆå¤§ï¼Œå› ä¸ºæ— æ³•è¿›è¡Œé¢„å‘å¸ƒï¼Œæ‰€ä»¥å—æ®µåç§°éœ€è¦æ…Žé‡è€ƒè™‘。 说明:MySQL 在 Windows 下ä¸åŒºåˆ†å¤§å°å†™ï¼Œä½†åœ¨ Linux 下默认是区分大å°å†™ã€‚å› æ¤ï¼Œæ•°æ®åº“ åã€è¡¨åã€å—段å,都ä¸å…è®¸å‡ºçŽ°ä»»ä½•å¤§å†™å—æ¯ï¼Œé¿å…节外生æžã€‚ æ£ä¾‹ï¼šaliyun_admin,rdc_config,level3_name å例:AliyunAdmin,rdcConfig,level_3_name ### 3. ã€å¼ºåˆ¶ã€‘表åä¸ä½¿ç”¨å¤æ•°åè¯ã€‚ 说明:表å应该仅仅表示表里é¢çš„实体内容,ä¸åº”该表示实体数é‡ï¼Œå¯¹åº”于 DO ç±»åä¹Ÿæ˜¯å•æ•° å½¢å¼ï¼Œç¬¦åˆè¡¨è¾¾ä¹ 惯。 ### 4. ã€å¼ºåˆ¶ã€‘ç¦ç”¨ä¿ç•™å—,如 descã€rangeã€matchã€delayed ç‰ï¼Œè¯·å‚考 MySQL 官方ä¿ç•™å—。 ### 5. ã€å¼ºåˆ¶ã€‘主键索引å为 pk_å—æ®µå;唯一索引å为 uk_å—æ®µå;普通索引å则为 idx_å—æ®µå。 说明:pk_ å³ primary keyï¼›uk_ å³ unique keyï¼›idx_ å³ index 的简称。 ### 6. ã€å¼ºåˆ¶ã€‘å°æ•°ç±»åž‹ä¸º decimalï¼Œç¦æ¢ä½¿ç”¨ float å’Œ double。 说明:float å’Œ double 在å˜å‚¨çš„æ—¶å€™ï¼Œå˜åœ¨ç²¾åº¦æŸå¤±çš„问题,很å¯èƒ½åœ¨å€¼çš„æ¯”è¾ƒæ—¶ï¼Œå¾—åˆ°ä¸ æ£ç¡®çš„结果。如果å˜å‚¨çš„æ•°æ®èŒƒå›´è¶…过 decimal çš„èŒƒå›´ï¼Œå»ºè®®å°†æ•°æ®æ‹†æˆæ•´æ•°å’Œå°æ•°åˆ†å¼€å˜å‚¨ã€‚ ### 7. ã€å¼ºåˆ¶ã€‘如果å˜å‚¨çš„å—ç¬¦ä¸²é•¿åº¦å‡ ä¹Žç›¸ç‰ï¼Œä½¿ç”¨ char 定长å—符串类型。 ### 8. ã€å¼ºåˆ¶ã€‘varchar 是å¯å˜é•¿å—符串,ä¸é¢„先分é…å˜å‚¨ç©ºé—´ï¼Œé•¿åº¦ä¸è¦è¶…过 5000,如果å˜å‚¨é•¿ 度大于æ¤å€¼ï¼Œå®šä¹‰å—段类型为 text,独立出æ¥ä¸€å¼ 表,用主键æ¥å¯¹åº”,é¿å…å½±å“å…¶å®ƒå—æ®µç´¢ 引效率。 ### 9. ã€å¼ºåˆ¶ã€‘è¡¨å¿…å¤‡ä¸‰å—æ®µï¼šid, gmt_create, gmt_modified。 è¯´æ˜Žï¼šå…¶ä¸ id 必为主键,类型为 unsigned bigintã€å•è¡¨æ—¶è‡ªå¢žã€æ¥é•¿ä¸º 1。gmt_create, gmt_modified 的类型å‡ä¸º date_time 类型,å‰è€…现在时表示主动创建,åŽè€…过去分è¯è¡¨ç¤ºè¢« 动更新。 ### 10. ã€æŽ¨èã€‘è¡¨çš„å‘½åæœ€å¥½æ˜¯åŠ ä¸Šâ€œä¸šåŠ¡åç§°_表的作用â€ã€‚ æ£ä¾‹ï¼šalipay_task / force_project / trade_config ### 11. ã€æŽ¨è】库å与应用åç§°å°½é‡ä¸€è‡´ã€‚ ### 12. ã€æŽ¨èã€‘å¦‚æžœä¿®æ”¹å—æ®µå«ä¹‰æˆ–坹嗿®µè¡¨ç¤ºçš„状æ€è¿½åŠ æ—¶ï¼Œéœ€è¦åŠæ—¶æ›´æ–°å—段注释。 ### 13. ã€æŽ¨èã€‘å—æ®µå…许适当冗余,以æé«˜æŸ¥è¯¢æ€§èƒ½ï¼Œä½†å¿…须考虑数æ®ä¸€è‡´ã€‚冗余嗿®µåº”éµå¾ªï¼š 1ï¼‰ä¸æ˜¯é¢‘ç¹ä¿®æ”¹çš„å—æ®µã€‚ 2ï¼‰ä¸æ˜¯ varchar è¶…é•¿å—æ®µï¼Œæ›´ä¸èƒ½æ˜¯ text å—æ®µã€‚ æ£ä¾‹ï¼šå•†å“类目åç§°ä½¿ç”¨é¢‘çŽ‡é«˜ï¼Œå—æ®µé•¿åº¦çŸï¼Œå称基本一æˆä¸å˜ï¼Œå¯åœ¨ç›¸å…³è”的表ä¸å†—ä½™å˜ å‚¨ç±»ç›®å称,é¿å…å…³è”æŸ¥è¯¢ã€‚ ### 14. ã€æŽ¨è】å•表行数超过 500 万行或者å•表容é‡è¶…过 2GBï¼Œæ‰æŽ¨è进行分库分表。 说明:如果预计三年åŽçš„æ•°æ®é‡æ ¹æœ¬è¾¾ä¸åˆ°è¿™ä¸ªçº§åˆ«ï¼Œè¯·ä¸è¦åœ¨åˆ›å»ºè¡¨æ—¶å°±åˆ†åº“分表。 ### 15. ã€å‚考】åˆé€‚çš„å—符å˜å‚¨é•¿åº¦ï¼Œä¸ä½†èŠ‚çº¦æ•°æ®åº“表空间ã€èŠ‚çº¦ç´¢å¼•å˜å‚¨ï¼Œæ›´é‡è¦çš„æ˜¯æå‡æ£€ 索速度。 æ£ä¾‹ï¼šå¦‚ä¸‹è¡¨ï¼Œå…¶ä¸æ— 符å·å€¼å¯ä»¥é¿å…误å˜è´Ÿæ•°ï¼Œä¸”扩大了表示范围。 对象 年龄区间 类型 å—节 表示范围 人 150 å²ä¹‹å†… unsigned tinyint 1 æ— ç¬¦å·å€¼ï¼š0 到 255 龟 æ•°ç™¾å² unsigned smallint 2 æ— ç¬¦å·å€¼ï¼š0 到 65535 æé¾™åŒ–石 æ•°åƒä¸‡å¹´ unsigned int 4 æ— ç¬¦å·å€¼ï¼š0 到约 42.9 亿 太阳 约 50 亿年 unsigned bigint 8 æ— ç¬¦å·å€¼ï¼š0 到约 10 çš„ 19 次方 ## (二)索引规约 ### 1. ã€å¼ºåˆ¶ã€‘ä¸šåŠ¡ä¸Šå…·æœ‰å”¯ä¸€ç‰¹æ€§çš„å—æ®µï¼Œå³ä½¿æ˜¯å¤šä¸ªå—段的组åˆï¼Œä¹Ÿå¿…须建æˆå”¯ä¸€ç´¢å¼•。 说明:ä¸è¦ä»¥ä¸ºå”¯ä¸€ç´¢å¼•å½±å“了 insert 速度,这个速度æŸè€—å¯ä»¥å¿½ç•¥ï¼Œä½†æé«˜æŸ¥æ‰¾é€Ÿåº¦æ˜¯æ˜Ž 显的;å¦å¤–,å³ä½¿åœ¨åº”用层åšäº†éžå¸¸å®Œå–„çš„æ ¡éªŒæŽ§åˆ¶ï¼Œåªè¦æ²¡æœ‰å”¯ä¸€ç´¢å¼•ï¼Œæ ¹æ®å¢¨è²å®šå¾‹ï¼Œå¿… ç„¶æœ‰è„æ•°æ®äº§ç”Ÿã€‚ ### 2. ã€å¼ºåˆ¶ã€‘è¶…è¿‡ä¸‰ä¸ªè¡¨ç¦æ¢ joinã€‚éœ€è¦ join çš„å—æ®µï¼Œæ•°æ®ç±»åž‹å¿…é¡»ç»å¯¹ä¸€è‡´ï¼›å¤šè¡¨å…³è”查询时, ä¿è¯è¢«å…³è”çš„å—æ®µéœ€è¦æœ‰ç´¢å¼•。 说明:å³ä½¿åŒè¡¨ join ä¹Ÿè¦æ³¨æ„表索引ã€SQL 性能。 ### 3. ã€å¼ºåˆ¶ã€‘在 varchar å—æ®µä¸Šå»ºç«‹ç´¢å¼•时,必须指定索引长度,没必è¦å¯¹å…¨å—æ®µå»ºç«‹ç´¢å¼•ï¼Œæ ¹æ® å®žé™…æ–‡æœ¬åŒºåˆ†åº¦å†³å®šç´¢å¼•é•¿åº¦å³å¯ã€‚ 说明:索引的长度与区分度是一对矛盾体,一般对å—符串类型数æ®ï¼Œé•¿åº¦ä¸º 20 的索引,区分 度会高达 90%以上,å¯ä»¥ä½¿ç”¨ count(distinct left(列å, 索引长度))/count(*)的区分度 æ¥ç¡®å®šã€‚ ### 4. ã€å¼ºåˆ¶ã€‘页颿œç´¢ä¸¥ç¦å·¦æ¨¡ç³Šæˆ–者全模糊,如果需è¦è¯·èµ°æœç´¢å¼•擎æ¥è§£å†³ã€‚ 说明:索引文件具有 B-Tree 的最左å‰ç¼€åŒ¹é…ç‰¹æ€§ï¼Œå¦‚æžœå·¦è¾¹çš„å€¼æœªç¡®å®šï¼Œé‚£ä¹ˆæ— æ³•ä½¿ç”¨æ¤ç´¢ 引。 ### 5. ã€æŽ¨è】如果有 order by 的场景,请注æ„åˆ©ç”¨ç´¢å¼•çš„æœ‰åºæ€§ã€‚order by 最åŽçš„å—æ®µæ˜¯ç»„åˆ ç´¢å¼•çš„ä¸€éƒ¨åˆ†ï¼Œå¹¶ä¸”æ”¾åœ¨ç´¢å¼•ç»„åˆé¡ºåºçš„æœ€åŽï¼Œé¿å…出现 file_sort çš„æƒ…å†µï¼Œå½±å“æŸ¥è¯¢æ€§èƒ½ã€‚ æ£ä¾‹ï¼šwhere a=? and b=? order by c; 索引:a_b_c åä¾‹ï¼šç´¢å¼•ä¸æœ‰èŒƒå›´æŸ¥æ‰¾ï¼Œé‚£ä¹ˆç´¢å¼•æœ‰åºæ€§æ— 法利用,如:WHERE a>10 ORDER BY b; 索引 a_b æ— æ³•æŽ’åºã€‚ ### 6. ã€æŽ¨è】利用覆盖索引æ¥è¿›è¡ŒæŸ¥è¯¢æ“作,é¿å…回表。 说明:如果一本书需è¦çŸ¥é“第 11 ç« æ˜¯ä»€ä¹ˆæ ‡é¢˜ï¼Œä¼šç¿»å¼€ç¬¬ 11 ç« å¯¹åº”çš„é‚£ä¸€é¡µå—?目录æµè§ˆ 一下就好,这个目录就是起到覆盖索引的作用。 æ£ä¾‹ï¼šèƒ½å¤Ÿå»ºç«‹ç´¢å¼•çš„ç§ç±»ï¼šä¸»é”®ç´¢å¼•ã€å”¯ä¸€ç´¢å¼•ã€æ™®é€šç´¢å¼•ï¼Œè€Œè¦†ç›–ç´¢å¼•æ˜¯ä¸€ç§æŸ¥è¯¢çš„ä¸€ç§ æ•ˆæžœï¼Œç”¨ explain 的结果,extra 列会出现:using index。 ### 7. ã€æŽ¨èã€‘åˆ©ç”¨å»¶è¿Ÿå…³è”æˆ–è€…åæŸ¥è¯¢ä¼˜åŒ–超多分页场景。 说明:MySQL 并䏿˜¯è·³è¿‡ offset è¡Œï¼Œè€Œæ˜¯å– offset+N 行,然åŽè¿”å›žæ”¾å¼ƒå‰ offset 行,返回 N 行,那当 offset 特别大的时候,效率就éžå¸¸çš„低下,è¦ä¹ˆæŽ§åˆ¶è¿”回的总页数,è¦ä¹ˆå¯¹è¶…过 特定阈值的页数进行 SQL 改写。 æ£ä¾‹ï¼šå…ˆå¿«é€Ÿå®šä½éœ€è¦èŽ·å–çš„ id 段,然åŽå†å…³è”: SELECT a.* FROM 表 1 a, (select id from 表 1 where æ¡ä»¶ LIMIT 100000,20 ) b where a.id=b.id ### 8. ã€æŽ¨è】SQL æ€§èƒ½ä¼˜åŒ–çš„ç›®æ ‡ï¼šè‡³å°‘è¦è¾¾åˆ° range çº§åˆ«ï¼Œè¦æ±‚是 ref 级别,如果å¯ä»¥æ˜¯ consts 最好。 说明: 1)consts å•è¡¨ä¸æœ€å¤šåªæœ‰ä¸€ä¸ªåŒ¹é…行(主键或者唯一索引),在优化阶段å³å¯è¯»å–到数æ®ã€‚ 2)ref 指的是使用普通的索引(normal index)。 3)range 对索引进行范围检索。 å例:explain 表的结果,type=indexï¼Œç´¢å¼•ç‰©ç†æ–‡ä»¶å…¨æ‰«æï¼Œé€Ÿåº¦éžå¸¸æ…¢ï¼Œè¿™ä¸ª index 级 别比较 range è¿˜ä½Žï¼Œä¸Žå…¨è¡¨æ‰«ææ˜¯å°å·«è§å¤§å·«ã€‚ ### 9. ã€æŽ¨è】建组åˆç´¢å¼•的时候,区分度最高的在最左边。 æ£ä¾‹ï¼šå¦‚æžœ where a=? and b=? ,a åˆ—çš„å‡ ä¹ŽæŽ¥è¿‘äºŽå”¯ä¸€å€¼ï¼Œé‚£ä¹ˆåªéœ€è¦å•建 idx_a ç´¢å¼•å³ å¯ã€‚ 说明:å˜åœ¨éžç‰å·å’Œç‰å·æ··åˆåˆ¤æ–æ¡ä»¶æ—¶ï¼Œåœ¨å»ºç´¢å¼•时,请把ç‰å·æ¡ä»¶çš„列å‰ç½®ã€‚如:where a>? and b=? 那么å³ä½¿ a 的区分度更高,也必须把 b 放在索引的最å‰åˆ—。 ### 10. ã€æŽ¨è】防æ¢å› å—æ®µç±»åž‹ä¸åŒé€ æˆçš„éšå¼è½¬æ¢ï¼Œå¯¼è‡´ç´¢å¼•失效。 ### 11. ã€å‚考】创建索引时é¿å…有如下æžç«¯è¯¯è§£ï¼š 1ï¼‰å®æ»¥å‹¿ç¼ºã€‚认为一个查询就需è¦å»ºä¸€ä¸ªç´¢å¼•。 2)å®ç¼ºå‹¿æ»¥ã€‚认为索引会消耗空间ã€ä¸¥é‡æ‹–慢更新和新增速度。 3)抵制惟一索引。认为业务的惟一性一律需è¦åœ¨åº”ç”¨å±‚é€šè¿‡â€œå…ˆæŸ¥åŽæ’â€æ–¹å¼è§£å†³ã€‚ ## (三)SQL è¯å¥ ### 1. ã€å¼ºåˆ¶ã€‘ä¸è¦ä½¿ç”¨ count(列å)或 count(常é‡)æ¥æ›¿ä»£ count(*),count(*)是 SQL92 定义的 æ ‡å‡†ç»Ÿè®¡è¡Œæ•°çš„è¯æ³•,跟数æ®åº“æ— å…³ï¼Œè·Ÿ NULL å’Œéž NULL æ— å…³ã€‚ 说明:count(*)会统计值为 NULL 的行,而 count(列å)ä¸ä¼šç»Ÿè®¡æ¤åˆ—为 NULL 值的行。 ### 2. ã€å¼ºåˆ¶ã€‘count(distinct col) 计算该列除 NULL 之外的ä¸é‡å¤è¡Œæ•°ï¼Œæ³¨æ„ count(distinct col1, col2) 如果其ä¸ä¸€åˆ—全为 NULL,那么å³ä½¿å¦ä¸€åˆ—有ä¸åŒçš„值,也返回为 0。 ### 3. ã€å¼ºåˆ¶ã€‘当æŸä¸€åˆ—的值全是 NULL 时,count(col)的返回结果为 0,但 sum(col)的返回结果为 NULLï¼Œå› æ¤ä½¿ç”¨ sum()æ—¶éœ€æ³¨æ„ NPE 问题。 æ£ä¾‹ï¼šå¯ä»¥ä½¿ç”¨å¦‚ä¸‹æ–¹å¼æ¥é¿å… sum çš„ NPE 问题:SELECT IF(ISNULL(SUM(g)),0,SUM(g)) FROM table; ### 4. ã€å¼ºåˆ¶ã€‘使用 ISNULL()æ¥åˆ¤æ–是å¦ä¸º NULL 值。 说明:NULL 与任何值的直接比较都为 NULL。 1) NULL<>NULL 的返回结果是 NULLï¼Œè€Œä¸æ˜¯ false。 2) NULL=NULL 的返回结果是 NULLï¼Œè€Œä¸æ˜¯ true。 3) NULL<>1 的返回结果是 NULLï¼Œè€Œä¸æ˜¯ true。 ### 5. ã€å¼ºåˆ¶ã€‘在代ç ä¸å†™åˆ†é¡µæŸ¥è¯¢é€»è¾‘时,若 count 为 0 应直接返回,é¿å…执行åŽé¢çš„分页è¯å¥ã€‚ ### 6. ã€å¼ºåˆ¶ã€‘ä¸å¾—使用外键与级è”,一切外键概念必须在应用层解决。 说明:以å¦ç”Ÿå’Œæˆç»©çš„关系为例,å¦ç”Ÿè¡¨ä¸çš„ student_id是主键,那么æˆç»©è¡¨ä¸çš„ student_id 则为外键。如果更新å¦ç”Ÿè¡¨ä¸çš„ student_idï¼ŒåŒæ—¶è§¦å‘æˆç»©è¡¨ä¸çš„ student_id 更新,å³ä¸º çº§è”æ›´æ–°ã€‚å¤–é”®ä¸Žçº§è”æ›´æ–°é€‚ç”¨äºŽå•æœºä½Žå¹¶å‘,ä¸é€‚åˆåˆ†å¸ƒå¼ã€é«˜å¹¶å‘é›†ç¾¤ï¼›çº§è”æ›´æ–°æ˜¯å¼ºé˜» 塞,å˜åœ¨æ•°æ®åº“æ›´æ–°é£Žæš´çš„é£Žé™©ï¼›å¤–é”®å½±å“æ•°æ®åº“çš„æ’入速度。 ### 7. ã€å¼ºåˆ¶ã€‘ç¦æ¢ä½¿ç”¨å˜å‚¨è¿‡ç¨‹ï¼Œå˜å‚¨è¿‡ç¨‹éš¾ä»¥è°ƒè¯•å’Œæ‰©å±•ï¼Œæ›´æ²¡æœ‰ç§»æ¤æ€§ã€‚ ### 8. ã€å¼ºåˆ¶ã€‘æ•°æ®è®¢æ£æ—¶ï¼Œåˆ 除和修改记录时,è¦å…ˆ select,é¿å…å‡ºçŽ°è¯¯åˆ é™¤ï¼Œç¡®è®¤æ— è¯¯æ‰èƒ½æ‰§è¡Œæ›´æ–°è¯å¥ã€‚ ### 9. ã€æŽ¨è】in æ“作能é¿å…则é¿å…,若实在é¿å…ä¸äº†ï¼Œéœ€è¦ä»”细评估 in åŽè¾¹çš„集åˆå…ƒç´ æ•°é‡ï¼ŒæŽ§ 制在 1000 个之内。 ### 10. ã€å‚考】如果有全çƒåŒ–需è¦ï¼Œæ‰€æœ‰çš„å—符å˜å‚¨ä¸Žè¡¨ç¤ºï¼Œå‡ä»¥ utf-8 ç¼–ç ,注æ„å—符统计函数 的区别。 说明: SELECT LENGTH("è½»æ¾å·¥ä½œ")ï¼› 返回为 12 SELECT CHARACTER_LENGTH("è½»æ¾å·¥ä½œ")ï¼› 返回为 4 如果需è¦å˜å‚¨è¡¨æƒ…,那么选择 utfmb4 æ¥è¿›è¡Œå˜å‚¨ï¼Œæ³¨æ„它与 utf-8 ç¼–ç 的区别。 ### 11. ã€å‚考】TRUNCATE TABLE 比 DELETE 速度快,且使用的系统和事务日志资æºå°‘,但 TRUNCATE æ— äº‹åŠ¡ä¸”ä¸è§¦å‘ trigger,有å¯èƒ½é€ æˆäº‹æ•…,故ä¸å»ºè®®åœ¨å¼€å‘代ç ä¸ä½¿ç”¨æ¤è¯å¥ã€‚ 说明:TRUNCATE TABLE 在功能上与ä¸å¸¦ WHERE åå¥çš„ DELETE è¯å¥ç›¸åŒã€‚ ## (å››)ORM æ˜ å°„ ### 1. ã€å¼ºåˆ¶ã€‘在表查询ä¸ï¼Œä¸€å¾‹ä¸è¦ä½¿ç”¨ * ä½œä¸ºæŸ¥è¯¢çš„å—æ®µåˆ—表,需è¦å“ªäº›å—段必须明确写明。 说明:1ï¼‰å¢žåŠ æŸ¥è¯¢åˆ†æžå™¨è§£æžæˆæœ¬ã€‚2)增å‡å—段容易与 resultMap é…ç½®ä¸ä¸€è‡´ã€‚ ### 2. ã€å¼ºåˆ¶ã€‘POJO 类的布尔属性ä¸èƒ½åŠ is,而数æ®åº“å—æ®µå¿…é¡»åŠ is_ï¼Œè¦æ±‚在 resultMap ä¸è¿›è¡Œ å—æ®µä¸Žå±žæ€§ä¹‹é—´çš„æ˜ 射。 说明:å‚è§å®šä¹‰ POJO ç±»ä»¥åŠæ•°æ®åº“å—æ®µå®šä¹‰è§„定,在\<resultMap>ä¸å¢žåŠ æ˜ å°„ï¼Œæ˜¯å¿…é¡»çš„ã€‚ 在 MyBatis Generator 生æˆçš„代ç ä¸ï¼Œéœ€è¦è¿›è¡Œå¯¹åº”的修改。 ### 3. ã€å¼ºåˆ¶ã€‘ä¸è¦ç”¨ resultClass å½“è¿”å›žå‚æ•°ï¼Œå³ä½¿æ‰€æœ‰ç±»å±žæ€§å与数æ®åº“å—æ®µä¸€ä¸€å¯¹åº”,也需 è¦å®šä¹‰ï¼›å过æ¥ï¼Œæ¯ä¸€ä¸ªè¡¨ä¹Ÿå¿…然有一个与之对应。 说明:é…ç½®æ˜ å°„å…³ç³»ï¼Œä½¿å—æ®µä¸Ž DO 类解耦,方便维护。 ### 4. ã€å¼ºåˆ¶ã€‘sql.xml é…ç½®å‚æ•°ä½¿ç”¨ï¼š#{},#param# ä¸è¦ä½¿ç”¨${} æ¤ç§æ–¹å¼å®¹æ˜“出现 SQL 注入。 ### 5. ã€å¼ºåˆ¶ã€‘iBATIS 自带的 queryForList(String statementName,int start,int size)䏿ލ è使用。 è¯´æ˜Žï¼šå…¶å®žçŽ°æ–¹å¼æ˜¯åœ¨æ•°æ®åº“å–到statementName对应的SQLè¯å¥çš„æ‰€æœ‰è®°å½•,å†é€šè¿‡subList å– start,size çš„å集åˆã€‚ æ£ä¾‹ï¼šMap<String, Object> map = new HashMap<String, Object>(); map.put("start", start); map.put("size", size); ### 6. ã€å¼ºåˆ¶ã€‘ä¸å…许直接拿 HashMap 与 Hashtable 作为查询结果集的输出。 说明:resultClass=â€Hashtableâ€ï¼Œä¼šç½®å…¥å—段å和属性值,但是值的类型ä¸å¯æŽ§ã€‚ ### 7. ã€å¼ºåˆ¶ã€‘æ›´æ–°æ•°æ®è¡¨è®°å½•æ—¶ï¼Œå¿…é¡»åŒæ—¶æ›´æ–°è®°å½•对应的 gmt_modified å—æ®µå€¼ä¸ºå½“剿—¶é—´ã€‚ ### 8. ã€æŽ¨è】ä¸è¦å†™ä¸€ä¸ªå¤§è€Œå…¨çš„æ•°æ®æ›´æ–°æŽ¥å£ã€‚ä¼ å…¥ä¸º POJO 类,ä¸ç®¡æ˜¯ä¸æ˜¯è‡ªå·±çš„ç›®æ ‡æ›´æ–°å— æ®µï¼Œéƒ½è¿›è¡Œ update table set c1=value1,c2=value2,c3=value3; 这是ä¸å¯¹çš„。执行 SQL 时,ä¸è¦æ›´æ–°æ— æ”¹åŠ¨çš„å—æ®µï¼Œä¸€æ˜¯æ˜“å‡ºé”™ï¼›äºŒæ˜¯æ•ˆçŽ‡ä½Žï¼›ä¸‰æ˜¯å¢žåŠ binlog å˜å‚¨ã€‚ ### 9. ã€å‚考】@Transactional 事务ä¸è¦æ»¥ç”¨ã€‚äº‹åŠ¡ä¼šå½±å“æ•°æ®åº“çš„ QPS,å¦å¤–使用事务的地方需 è¦è€ƒè™‘儿–¹é¢çš„回滚方案,包括缓å˜å›žæ»šã€æœç´¢å¼•æ“Žå›žæ»šã€æ¶ˆæ¯è¡¥å¿ã€ç»Ÿè®¡ä¿®æ£ç‰ã€‚ ### 10. ã€å‚考】\<isEqual>ä¸çš„ compareValue 是与属性值对比的常é‡ï¼Œä¸€èˆ¬æ˜¯æ•°å—ï¼Œè¡¨ç¤ºç›¸ç‰æ—¶å¸¦ä¸Šæ¤æ¡ä»¶ï¼›\<isNotEmpty>表示ä¸ä¸ºç©ºä¸”ä¸ä¸º null 时执行;\<isNotNull>表示ä¸ä¸º null 值时 执行。 # å…ã€å·¥ç¨‹ç»“æž„ ## (一)应用分层 ### 1. ã€æŽ¨è】图ä¸é»˜è®¤ä¸Šå±‚ä¾èµ–于下层,ç®å¤´å…³ç³»è¡¨ç¤ºå¯ç›´æŽ¥ä¾èµ–,如:开放接å£å±‚å¯ä»¥ä¾èµ–于Web 层,也å¯ä»¥ç›´æŽ¥ä¾èµ–于 Service å±‚ï¼Œä¾æ¤ç±»æŽ¨ï¼š - 开放接å£å±‚:å¯ç›´æŽ¥å°è£… Service æ–¹æ³•æš´éœ²æˆ RPC 接å£ï¼›é€šè¿‡ Web å°è£…æˆ http 接å£ï¼›è¿›è¡Œ ç½‘å…³å®‰å…¨æŽ§åˆ¶ã€æµé‡æŽ§åˆ¶ç‰ã€‚ - 终端显示层:å„ä¸ªç«¯çš„æ¨¡æ¿æ¸²æŸ“并执行显示的层。当å‰ä¸»è¦æ˜¯ velocity 渲染,JS 渲染, JSP 渲染,移动端展示ç‰ã€‚ - Web å±‚ï¼šä¸»è¦æ˜¯å¯¹è®¿é—®æŽ§åˆ¶è¿›è¡Œè½¬å‘,å„ç±»åŸºæœ¬å‚æ•°æ ¡éªŒï¼Œæˆ–者ä¸å¤ç”¨çš„业务简å•处ç†ç‰ã€‚ - Service 层:相对具体的业务逻辑æœåŠ¡å±‚ã€‚ - Manager 层:通用业务处ç†å±‚,它有如下特å¾ï¼š 1) 对第三方平å°å°è£…的层,预处ç†è¿”回结果åŠè½¬åŒ–异常信æ¯ï¼› 2) 对 Service å±‚é€šç”¨èƒ½åŠ›çš„ä¸‹æ²‰ï¼Œå¦‚ç¼“å˜æ–¹æ¡ˆã€ä¸é—´ä»¶é€šç”¨å¤„ç†ï¼› 3) 与 DAO 层交互,对多个 DAO 的组åˆå¤ç”¨ã€‚ - DAO 层:数æ®è®¿é—®å±‚,与底层 MySQLã€Oracleã€Hbase ç‰è¿›è¡Œæ•°æ®äº¤äº’。 - å¤–éƒ¨æŽ¥å£æˆ–第三方平å°ï¼šåŒ…括其它部门 RPC 开放接å£ï¼ŒåŸºç¡€å¹³å°ï¼Œå…¶å®ƒå…¬å¸çš„ HTTP 接å£ã€‚ ### 2. ã€å‚考】 (分层异常处ç†è§„约)在 DAO å±‚ï¼Œäº§ç”Ÿçš„å¼‚å¸¸ç±»åž‹æœ‰å¾ˆå¤šï¼Œæ— æ³•ç”¨ç»†ç²’åº¦çš„å¼‚å¸¸è¿› 行 catch,使用 catch(Exception e)æ–¹å¼ï¼Œå¹¶ throw new DAOException(e),ä¸éœ€è¦æ‰“å° æ—¥å¿—ï¼Œå› ä¸ºæ—¥å¿—åœ¨ Manager/Service å±‚ä¸€å®šéœ€è¦æ•获并打到日志文件ä¸åŽ»ï¼Œå¦‚æžœåŒå°æœåС噍 冿‰“日志,浪费性能和å˜å‚¨ã€‚在 Service 层出现异常时,必须记录出错日志到ç£ç›˜ï¼Œå°½å¯èƒ½å¸¦ ä¸Šå‚æ•°ä¿¡æ¯ï¼Œç›¸å½“äºŽä¿æŠ¤æ¡ˆå‘现场。如果 Manager 层与 Service åŒæœºéƒ¨ç½²ï¼Œæ—¥å¿—æ–¹å¼ä¸Ž DAO 层处ç†ä¸€è‡´ï¼Œå¦‚果是å•独部署,则采用与 Service ä¸€è‡´çš„å¤„ç†æ–¹å¼ã€‚Web 层ç»ä¸åº”该继ç»å¾€ä¸Š æŠ›å¼‚å¸¸ï¼Œå› ä¸ºå·²ç»å¤„于顶层,如果æ„è¯†åˆ°è¿™ä¸ªå¼‚å¸¸å°†å¯¼è‡´é¡µé¢æ— 法æ£å¸¸æ¸²æŸ“,那么就应该直接 跳转到å‹å¥½é”™è¯¯é¡µé¢ï¼ŒåŠ ä¸Šç”¨æˆ·å®¹æ˜“ç†è§£çš„错误æç¤ºä¿¡æ¯ã€‚开放接å£å±‚è¦å°†å¼‚å¸¸å¤„ç†æˆé”™è¯¯ç å’Œé”™è¯¯ä¿¡æ¯æ–¹å¼è¿”回。 ### 3. ã€å‚考】分层领域模型规约: - DO(Data Object):与数æ®åº“表结构一一对应,通过 DAO 层å‘ä¸Šä¼ è¾“æ•°æ®æºå¯¹è±¡ã€‚ - DTO(Data Transfer Object):数æ®ä¼ 输对象,Service 或 Manager å‘å¤–ä¼ è¾“çš„å¯¹è±¡ã€‚ - BO(Business Object):业务对象。由 Service 层输出的å°è£…业务逻辑的对象。 - AO(Application Object):应用对象。在 Web 层与 Service 层之间抽象的å¤ç”¨å¯¹è±¡æ¨¡åž‹ï¼Œ æžä¸ºè´´è¿‘展示层,å¤ç”¨åº¦ä¸é«˜ã€‚ - VO(View Object):显示层对象,通常是 Web 呿¨¡æ¿æ¸²æŸ“å¼•æ“Žå±‚ä¼ è¾“çš„å¯¹è±¡ã€‚ - Queryï¼šæ•°æ®æŸ¥è¯¢å¯¹è±¡ï¼Œå„层接收上层的查询请求。注æ„超过 2 ä¸ªå‚æ•°çš„æŸ¥è¯¢å°è£…ï¼Œç¦æ¢ 使用 Map ç±»æ¥ä¼ 输。 ## (二)二方库ä¾èµ– ### 1. ã€å¼ºåˆ¶ã€‘定义 GAV éµä»Žä»¥ä¸‹è§„则: 1) GroupID æ ¼å¼ï¼šcom.{å…¬å¸/BU }.业务线.[å业务线],最多 4 级。 说明:{å…¬å¸/BU} 例如:alibaba/taobao/tmall/aliexpress ç‰ BU 一级;å业务线å¯é€‰ã€‚ æ£ä¾‹ï¼šcom.taobao.jstorm 或 com.alibaba.dubbo.register 2) ArtifactID æ ¼å¼ï¼šäº§å“线å-模å—å。è¯ä¹‰ä¸é‡å¤ä¸é—æ¼ï¼Œå…ˆåˆ°ä¸å¤®ä»“库去查è¯ä¸€ä¸‹ã€‚ æ£ä¾‹ï¼šdubbo-client / fastjson-api / jstorm-tool 3) Version:详细规定å‚考下方。 ### 2. ã€å¼ºåˆ¶ã€‘二方库版本å·å‘½åæ–¹å¼ï¼šä¸»ç‰ˆæœ¬å·.次版本å·.ä¿®è®¢å· 1) 主版本å·ï¼šäº§å“æ–¹å‘æ”¹å˜ï¼Œæˆ–者大规模 API ä¸å…¼å®¹ï¼Œæˆ–者架构ä¸å…¼å®¹å‡çº§ã€‚ 2) 次版本å·ï¼šä¿æŒç›¸å¯¹å…¼å®¹æ€§ï¼Œå¢žåР䏻è¦åŠŸèƒ½ç‰¹æ€§ï¼Œå½±å“范围æžå°çš„ API ä¸å…¼å®¹ä¿®æ”¹ã€‚ 3) 修订å·ï¼šä¿æŒå®Œå…¨å…¼å®¹æ€§ï¼Œä¿®å¤ BUGã€æ–°å¢žæ¬¡è¦åŠŸèƒ½ç‰¹æ€§ç‰ã€‚ 说明:注æ„起始版本å·å¿…须为:1.0.0ï¼Œè€Œä¸æ˜¯ 0.0.1 æ£å¼å‘布的类库必须先去ä¸å¤®ä»“库进 行查è¯ï¼Œä½¿ç‰ˆæœ¬å·æœ‰å»¶ç»æ€§ï¼Œæ£å¼ç‰ˆæœ¬å·ä¸å…许覆盖å‡çº§ã€‚如当å‰ç‰ˆæœ¬ï¼š1.3.3,那么下一个 åˆç†çš„版本å·ï¼š1.3.4 或 1.4.0 或 2.0.0 ### 3. ã€å¼ºåˆ¶ã€‘线上应用ä¸è¦ä¾èµ– SNAPSHOT 版本(安全包除外)。 说明:ä¸ä¾èµ– SNAPSHOT 版本是ä¿è¯åº”用å‘å¸ƒçš„å¹‚ç‰æ€§ã€‚å¦å¤–,也å¯ä»¥åŠ å¿«ç¼–è¯‘æ—¶çš„æ‰“åŒ…æž„å»ºã€‚ ### 4. ã€å¼ºåˆ¶ã€‘二方库的新增或å‡çº§ï¼Œä¿æŒé™¤åŠŸèƒ½ç‚¹ä¹‹å¤–çš„å…¶å®ƒ jar 包仲è£ç»“æžœä¸å˜ã€‚如果有改å˜ï¼Œ 必须明确评估和验è¯ï¼Œå»ºè®®è¿›è¡Œ dependency:resolve å‰åŽä¿¡æ¯æ¯”对,如果仲è£ç»“果完全ä¸ä¸€ 致,那么通过 dependency:tree 命令,找出差异点,进行\<excludes>排除 jar 包。 ### 5. ã€å¼ºåˆ¶ã€‘二方库里å¯ä»¥å®šä¹‰æžšä¸¾ç±»åž‹ï¼Œå‚æ•°å¯ä»¥ä½¿ç”¨æžšä¸¾ç±»åž‹ï¼Œä½†æ˜¯æŽ¥å£è¿”回值ä¸å…许使用枚 ä¸¾ç±»åž‹æˆ–è€…åŒ…å«æžšä¸¾ç±»åž‹çš„ POJO 对象。 ### 6. ã€å¼ºåˆ¶ã€‘ä¾èµ–于一个二方库群时,必须定义一个统一的版本å˜é‡ï¼Œé¿å…版本å·ä¸ä¸€è‡´ã€‚ 说明:ä¾èµ– springframework-core,-context,-beans,它们都是åŒä¸€ä¸ªç‰ˆæœ¬ï¼Œå¯ä»¥å®šä¹‰ä¸€ 个å˜é‡æ¥ä¿å˜ç‰ˆæœ¬ï¼š${spring.version},定义ä¾èµ–的时候,引用该版本。 ### 7. ã€å¼ºåˆ¶ã€‘ç¦æ¢åœ¨å项目的 pom ä¾èµ–ä¸å‡ºçŽ°ç›¸åŒçš„ GroupId,相åŒçš„ ArtifactId,但是ä¸åŒçš„ Version。 说明:在本地调试时会使用å„å项目指定的版本å·ï¼Œä½†æ˜¯åˆå¹¶æˆä¸€ä¸ª war,åªèƒ½æœ‰ä¸€ä¸ªç‰ˆæœ¬å· 出现在最åŽçš„ lib 目录ä¸ã€‚å¯èƒ½å‡ºçŽ°çº¿ä¸‹è°ƒè¯•æ˜¯æ£ç¡®çš„,å‘布到线上å´å‡ºæ•…障的问题。 ### 8. ã€æŽ¨è】所有 pom 文件ä¸çš„ä¾èµ–声明放在\<dependencies>è¯å¥å—ä¸ï¼Œæ‰€æœ‰ç‰ˆæœ¬ä»²è£æ”¾åœ¨\<dependencyManagement>è¯å¥å—ä¸ã€‚ 说明:\<dependencyManagement>é‡Œåªæ˜¯å£°æ˜Žç‰ˆæœ¬ï¼Œå¹¶ä¸å®žçŽ°å¼•å…¥ï¼Œå› æ¤åé¡¹ç›®éœ€è¦æ˜¾å¼çš„声 明ä¾èµ–,version å’Œ scope 都读å–自父 pom。而\<dependencies>所有声明在主 pom çš„ \<dependencies>里的ä¾èµ–都会自动引入,并默认被所有的å项目继承。 ### 9. ã€æŽ¨è】二方库ä¸è¦æœ‰é…置项,最低é™åº¦ä¸è¦å†å¢žåŠ é…置项。 ### 10. ã€å‚考】为é¿å…应用二方库的ä¾èµ–冲çªé—®é¢˜ï¼ŒäºŒæ–¹åº“å‘布者应当éµå¾ªä»¥ä¸‹åŽŸåˆ™ï¼š 1ï¼‰ç²¾ç®€å¯æŽ§åŽŸåˆ™ã€‚ç§»é™¤ä¸€åˆ‡ä¸å¿…è¦çš„ API å’Œä¾èµ–,åªåŒ…å« Service APIã€å¿…è¦çš„领域模型对 象ã€Utils ç±»ã€å¸¸é‡ã€æžšä¸¾ç‰ã€‚如果ä¾èµ–å…¶å®ƒäºŒæ–¹åº“ï¼Œå°½é‡æ˜¯ provided 引入,让二方库使用 者去ä¾èµ–具体版本å·ï¼›æ— log 具体实现,åªä¾èµ–日志框架。 2)稳定å¯è¿½æº¯åŽŸåˆ™ã€‚æ¯ä¸ªç‰ˆæœ¬çš„å˜åŒ–应该被记录,二方库由è°ç»´æŠ¤ï¼Œæºç 在哪里,都需è¦èƒ½ 方便查到。除éžç”¨æˆ·ä¸»åЍå‡çº§ç‰ˆæœ¬ï¼Œå¦åˆ™å…¬å…±äºŒæ–¹åº“的行为ä¸åº”该å‘生å˜åŒ–。 ## (三)æœåС噍 ### 1. ã€æŽ¨èã€‘é«˜å¹¶å‘æœåŠ¡å™¨å»ºè®®è°ƒå° TCP å议的 time_wait 超时时间。 说明:æ“作系统默认 240 ç§’åŽï¼Œæ‰ä¼šå…³é—处于 time_wait 状æ€çš„连接,在高并å‘è®¿é—®ä¸‹ï¼Œæœ åŠ¡å™¨ç«¯ä¼šå› ä¸ºå¤„äºŽ time_wait 的连接数太多,å¯èƒ½æ— 法建立新的连接,所以需è¦åœ¨æœåŠ¡å™¨ä¸Š è°ƒå°æ¤ç‰å¾…值。 æ£ä¾‹ï¼šåœ¨ linux æœåŠ¡å™¨ä¸Šè¯·é€šè¿‡å˜æ›´/etc/sysctl.conf 文件去修改该缺çœå€¼ï¼ˆç§’): net.ipv4.tcp_fin_timeout = 30 ### 2. ã€æŽ¨è】调大æœåŠ¡å™¨æ‰€æ”¯æŒçš„æœ€å¤§æ–‡ä»¶å¥æŸ„数(File Descriptor,简写为 fd)。 è¯´æ˜Žï¼šä¸»æµæ“作系统的设计是将 TCP/UDP è¿žæŽ¥é‡‡ç”¨ä¸Žæ–‡ä»¶ä¸€æ ·çš„æ–¹å¼åŽ»ç®¡ç†ï¼Œå³ä¸€ä¸ªè¿žæŽ¥å¯¹ 应于一个 fd。主æµçš„ linux æœåŠ¡å™¨é»˜è®¤æ‰€æ”¯æŒæœ€å¤§ fd æ•°é‡ä¸º 1024,当并å‘连接数很大时很 å®¹æ˜“å› ä¸º fd ä¸è¶³è€Œå‡ºçŽ°â€œopen too many filesâ€é”™è¯¯ï¼Œå¯¼è‡´æ–°çš„è¿žæŽ¥æ— æ³•å»ºç«‹ã€‚ 建议将 linux æœåŠ¡å™¨æ‰€æ”¯æŒçš„æœ€å¤§å¥æŸ„数调高数å€ï¼ˆä¸ŽæœåŠ¡å™¨çš„å†…å˜æ•°é‡ç›¸å…³ï¼‰ã€‚ ### 3. ã€æŽ¨è】给 JVM 设置-XX:+HeapDumpOnOutOfMemoryError 傿•°ï¼Œè®© JVM 碰到 OOM 场景时输出dump ä¿¡æ¯ã€‚ 说明:OOM çš„å‘生是有概率的,甚至有规律地相隔数月æ‰å‡ºçŽ°ä¸€ä¾‹ï¼Œå‡ºçŽ°æ—¶çš„çŽ°åœºä¿¡æ¯å¯¹æŸ¥é”™ éžå¸¸æœ‰ä»·å€¼ã€‚ ### 4. ã€æŽ¨è】在线上生产环境,JVM çš„ Xms å’Œ Xmx è®¾ç½®ä¸€æ ·å¤§å°çš„内å˜å®¹é‡ï¼Œé¿å…在 GC åŽè°ƒæ•´å †å¤§å°å¸¦æ¥çš„压力。 ### 5. ã€å‚考】æœåŠ¡å™¨å†…éƒ¨é‡å®šå‘使用 forward;外部é‡å®šå‘地å€ä½¿ç”¨ URL 拼装工具类æ¥ç”Ÿæˆï¼Œå¦åˆ™ä¼šå¸¦æ¥ URL 维护ä¸ä¸€è‡´çš„问题和潜在的安全风险。 # 附 1ï¼šç‰ˆæœ¬åŽ†å² | ç‰ˆæœ¬å· | 更新日期 | 备注 | | :-- | :-- | :-- | | 1.0.0 | 2017.2.9 | 阿里巴巴集团æ£å¼å¯¹å¤–å‘布 | | 1.0.1 | 2017.2.13 | 1ï¼‰ä¿®æ£ String[]çš„å‰åŽçŸ›ç›¾ã€‚<br>2)vm ä¿®æ£æˆ velocity。<br>3ï¼‰ä¿®æ£ countdown æè¿°é”™è¯¯ã€‚ | | 1.0.2 | 2017.2.20 | 1)去除文底水å°ã€‚<br>2)数æ®ç±»åž‹ä¸å¼•用太阳系年龄问题。<br>3)修æ£å…³äºŽå¼‚常和方法ç¾å的部分æè¿°ã€‚<br>4ï¼‰ä¿®æ£ final æè¿°ã€‚<br>5)去除 Comparator 部分æè¿°ã€‚ | | 1.1.0 | 2017.2.27 | 1ï¼‰å¢žåŠ å‰è¨€ã€‚<br>2ï¼‰å¢žåŠ <? extends T>æè¿°å’Œè¯´æ˜Žã€‚<br>3ï¼‰å¢žåŠ ç‰ˆæœ¬åŽ†å²ã€‚<br>4ï¼‰å¢žåŠ ä¸“æœ‰åè¯è§£é‡Šã€‚ | | 1.1.1 | 2017.3.31 | ä¿®æ£é¡µç 总数和部分示例。 | | 1.2.0 | 2017.5.20 | 1ï¼‰æ ¹æ®äº‘æ –ç¤¾åŒºçš„â€œèšèƒ½èŠâ€æ´»åЍå馈,对手册的页ç ã€æŽ’ç‰ˆã€æè¿°è¿›è¡Œä¿®æ£ã€‚<br>2ï¼‰å¢žåŠ final的适用场景æè¿°ã€‚3ï¼‰å¢žåŠ å…³äºŽé”的粒度的说明。<br>4ï¼‰å¢žåŠ â€œæŒ‡å®šé›†åˆå¤§å°â€çš„è¯¦ç»†è¯´æ˜Žä»¥åŠæ£å例。<br>5ï¼‰å¢žåŠ å«è¯å¥çš„示例代ç 。<br>6)明确数æ®åº“è¡¨ç¤ºåˆ é™¤æ¦‚å¿µçš„å—æ®µå为 is_deleted | | 1.3.0 | 2017.9.25 | å¢žåŠ å•元测试规约(PDF 终æžç‰ˆï¼‰ï¼Œé˜¿é‡Œå¼€æºçš„ IDE 代ç 规约检测æ’件:点æ¤ä¸‹è½½æ›´å¤šåŠæ—¶ä¿¡æ¯ï¼Œè¯·å…³æ³¨ã€Šã€‹å®˜æ–¹å…¬ä¼—å·ï¼š | # 附 2:本手册专有åè¯ 1. POJO(Plain Ordinary Java Object): 在本手册ä¸ï¼ŒPOJO ä¸“æŒ‡åªæœ‰ setter / getter / toString 的简å•类,包括 DO/DTO/BO/VO ç‰ã€‚ 2. GAV(GroupIdã€ArtifactctIdã€Version): Maven åæ ‡ï¼Œæ˜¯ç”¨æ¥å”¯ä¸€æ ‡è¯† jar 包。 3. OOP(Object Oriented Programming): 本手册泛指类ã€å¯¹è±¡çš„ç¼–ç¨‹å¤„ç†æ–¹å¼ã€‚ 4. ORM(Object Relation Mapping): å¯¹è±¡å…³ç³»æ˜ å°„ï¼Œå¯¹è±¡é¢†åŸŸæ¨¡åž‹ä¸Žåº•å±‚æ•°æ®ä¹‹é—´çš„转æ¢ï¼Œ 本文泛指 iBATIS, mybatis ç‰æ¡†æž¶ã€‚ 5. NPE(java.lang.NullPointerException): 空指针异常。 6. SOA(Service-Oriented Architecture): é¢å‘æœåŠ¡æž¶æž„ï¼Œå®ƒå¯ä»¥æ ¹æ®éœ€æ±‚é€šè¿‡ç½‘ç»œå¯¹æ¾æ•£ 耦åˆçš„粗粒度应用组件进行分布å¼éƒ¨ç½²ã€ç»„åˆå’Œä½¿ç”¨ï¼Œæœ‰åˆ©äºŽæå‡ç»„ä»¶å¯é‡ç”¨æ€§ï¼Œå¯ç»´æŠ¤æ€§ã€‚ 7. 一方库: 本工程内部å项目模å—ä¾èµ–的库(jar 包)。 8. 二方库: å…¬å¸å†…部å‘布到ä¸å¤®ä»“库,å¯ä¾›å…¬å¸å†…部其它应用ä¾èµ–的库(jar 包)。 9. 三方库: å…¬å¸ä¹‹å¤–的开æºåº“(jar 包)。 10. IDE(Integrated Development Environment): 用于æä¾›ç¨‹åºå¼€å‘环境的应用程åºï¼Œä¸€ 般包括代ç 编辑器ã€ç¼–译器ã€è°ƒè¯•器和图形用户界é¢ç‰å·¥å…·ï¼Œæœ¬ã€Šæ‰‹å†Œã€‹æ³›æŒ‡ IntelliJ IDEA å’Œ eclipse。 法律声明 本手册为阿里巴巴集团技术部的技术分享,版æƒå½’阿里巴巴集团所有,仅供大家交æµã€å¦ä¹ åŠç ”ç©¶ ä½¿ç”¨ï¼Œç¦æ¢ç”¨äºŽå•†ä¸šç”¨é€”,è¿è€…必究。