阿里巴巴编程规范---编程规约之命名风格篇

📅 发布时间:2026/7/7 6:26:22 👁️ 浏览次数:
阿里巴巴编程规范---编程规约之命名风格篇
一、编程规约一命名风格Ⅰ.代码中的命名均不能以下划线或美元符号开始也不能以下划线或美元符号结束。反例_name / __name / $name / name_ / name$ / name__原因1. 避免与 Java 语言 / 框架的特殊命名约定冲突Java 语法虽允许使用下划线_和美元符号$但这两个符号有隐含的 “系统级用途”美元符号$JVM 会自动为内部类生成以$分隔的类名例如OuterClass$InnerClass如果开发者自定义的命名以$开头 / 结尾如$user、user$可能与 JVM 生成的类名、框架动态生成的标识符冲突导致反射、序列化等操作异常。下划线_部分开源框架 / 工具如 MyBatis、Spring会将下划线开头的命名视为 “内部私有标识”若开发者随意使用如_name可能被工具误判为框架内部变量引发配置解析、字段映射错误。2. 提升团队代码的统一性和可读性下划线 / 美元符号开头 / 结尾无实际语义如name_、_age仅会增加视觉干扰破坏 “驼峰命名法 / 下划线分隔法” 的一致性团队协作时若允许这类命名会出现_name、name_、$name等混乱形式增加代码阅读和维护的成本新手需额外分辨符号的意义。3. 规避工具 / 编译器的兼容问题静态代码检查工具如 CheckStyle、PMD、代码格式化工具、甚至部分编译器对 “下划线 / 美元符号开头 / 结尾” 的命名处理逻辑不一致例如某些序列化框架FastJSON、Jackson解析name_时可能误判字段名边界导致前后端数据交互时字段映射失败部分代码检查工具会将这类命名标记为 “不规范”增加团队的代码评审和整改成本。Ⅱ.所有编程相关的命名严禁使用拼音与英文混合的方式更不允许直接使用中文的方式。正例ali / alibaba / taobao / cainiao/ aliyun/ youku / hangzhou 等国际通用的名称可视同英文。反例DaZhePromotion [打折] / getPingfenByName() [评分] / String fw[福娃] / int 某变量 3说明正确的英文拼写和语法可以让阅读者易于理解避免歧义。注意纯拼音命名方式更要避免采用。Ⅲ.代码和注释中都要避免使用任何语言的种族歧视性词语。正例日本人 / 印度人 / blockList / allowList / secondary反例RIBENGUIZI / Asan / blackList / whiteList / slaveⅣ.类名使用 UpperCamelCase 风格大驼峰但以下情形例外DO / BO / DTO / VO / AO /PO / UID 等。正例ForceCode / UserDO / HtmlDTO / XmlService / TcpUdpDeal / TaPromotion反例forcecode / UserDo / HTMLDto / XMLService / TCPUDPDeal / TAPromotion说明大驼峰写法类名首字母必须大写每个独立单词 / 语义单元的首字母也大写例外规则是DO/BO/DTO/VO/AO/PO/UID 等固定标识需全大写作为类名后缀时不可拆分 / 小写标识全称中文含义核心使用场景通俗举例DOData Object数据对象与数据库表结构一一对应仅包含字段和 get/set无业务逻辑用户表 user 对应 UserDO字段完全匹配 id、username、passwordBOBusiness Object业务对象封装核心业务逻辑可包含多个 DO或整合业务方法订单 BOOrderBO可包含订单 DO 用户 DO并有计算订单金额的方法DTOData Transfer Object数据传输对象用于跨层 / 跨系统传输数据如前端→后端、微服务间调用仅保留传输所需字段前端提交订单时用 OrderDTO 传递商品 ID、数量无需传递数据库主键VOView Object视图对象面向前端页面 / 视图封装展示所需数据含格式化、拼接后的字段页面展示用户信息时UserVO 包含 “用户名 格式化后的注册时间yyyy-MM-dd”AOApplication Object应用对象封装应用层逻辑介于 BO 和 DTO 之间处理接口入参校验、简单聚合接口入参 AOUserAO可校验手机号格式再转换为 BO 处理业务POPersistent Object持久化对象与 DO 类似更侧重 “持久化层DAO 层” 的对象部分场景与 DO 混用操作数据库时PO 通过 DAO 层写入 / 读取数据UIDUnique Identifier唯一标识符用于生成 / 存储全局唯一的标识如分布式 ID标识类 / 字段的用途订单 UIDOrderUID存储订单的全局唯一 ID或 UidGenerator 类生成唯一 IDⅤ.方法名、参数名、成员变量、局部变量都统一使用 lowerCamelCase 风格小驼峰写法。正例localValue / getHttpMessage() / inputUserId原因通过命名风格快速区分 “类 / 接口” 和 “方法 / 变量”提升代码可读性遵循 Java 官方规范和 JDK 源码惯例降低开发者的学习 / 适应成本避免与常量命名规则混淆同时适配主流开发工具提升团队协作效率。Ⅵ.常量命名全部大写单词间用下划线隔开力求语义表达完整清楚不要嫌名字长。Ⅶ.抽象类命名使用 Abstract 或 Base 开头异常类命名使用 Exception 结尾测试类命名以它要测试的类的名称开始以 Test 结尾Ⅷ.类型与中括号紧挨相连来表示数组。正例定义整形数组 int[] arrayDemo。反例在 main 参数中使用 String args[]来定义。原因贴合 Java “数组是独立类型” 的语义设计而非 “变量的属性”消除多变量声明时的歧义从根源上避免新手踩坑(例子如下代码对齐 Java 官方规范和 JDK 源码提升代码可读性与团队协作效率。(Java 官方文档《The Java™ Tutorials》明确将int[] array列为推荐写法int array[]仅作为 “兼容 C 语言的语法糖” 存在并非推荐用法。)// 写法1类型中括号正确 int[] a, b; // 语义a和b都是int数组类型无歧义 // 写法2变量中括号错误 int a[], b; // 语义a是int数组类型b是普通int类型90%的新手会误以为b也是数组Ⅸ.POJO 类中的任何布尔类型的变量都不要加 is 前缀否则部分框架解析会引起序列化错误。反例定义为基本数据类型 Boolean isDeleted 的属性它的方法也是 isDeleted()框架在反向解析的时 候“误以为”对应的属性名称是 deleted导致属性获取不到进而抛出异常。说明在本文 MySQL 规约中的建表约定第一条表达是与否的变量采用 is_xxx 的命名方式所以需要在resultMap设置从 is_xxx 到 xxx 的映射关系。原因要搞懂这个规则需先理清POJO 布尔属性的 getter/setter 生成规则、框架解析逻辑、数据库与 POJO 的命名衔接三个核心点1. 先明确布尔类型属性的 getter/setter 生成规则关键前提Java 中POJO 的属性会通过 IDE / 框架如 Lombok自动生成 getter/setter 方法布尔类型boolean/Boolean的生成规则和普通类型不同普通类型如String namegetter 是getName()setter 是setName()布尔类型如果属性名不带 is 前缀如Boolean deletedgetter 是isDeleted()而非getDeleted()setter 是setDeleted()如果属性名带 is 前缀如Boolean isDeletedgetter 还是isDeleted()框架不会生成getIsDeleted()setter 是setIsDeleted()。简单说布尔类型的 getter 默认以is开头和属性名是否带is无关 —— 这是框架解析出错的根源。2. 反例解析为什么加 is 前缀会导致序列化 / 解析错误框架MyBatis、Jackson、Spring 等在反序列化 / 数据映射时会通过 getter 方法名反向推导属性名核心逻辑是去掉 get/is 前缀 → 剩余部分首字母小写 → 得到 “预期的属性名”比如框架解析isDeleted()方法去掉is→ 剩余Deleted→ 首字母小写 → 认为属性名是deleted实际 POJO 的属性名是isDeleted框架想找deleted属性却找不到结果抛出 “属性不存在”“序列化失败”“数据映射为空” 等异常比如 MyBatis 查不到值、Jackson 返回 null3. MySQL 命名与 POJO 的衔接为什么需要 resultMap 映射这里有个 “命名规则的矛盾” 需要解决MySQL 规约数据库表中表达 “是 / 否” 的字段要求用is_xxx如is_deleted符合 SQL 的可读性一眼能看出是布尔字段POJO 规约布尔属性不能加is前缀如deleted避免框架解析错误矛盾的解决方案就是在 MyBatis 的resultMap中做 “字段名→属性名” 的映射总结这个规范的核心要点可归纳为 3 点布尔属性加is前缀会导致框架通过 getter 反向推导的属性名如deleted与实际属性名如isDeleted不匹配引发序列化 / 映射错误MySQL 用is_xxx命名布尔字段是为了可读性POJO 用xxx命名是为了适配框架解析规则两者的衔接依赖 MyBatis 的resultMap将数据库is_xxx字段映射到 POJO 的xxx属性兼顾两种规范。Ⅹ.包名统一使用小写点分隔符之间有且仅有一个自然语义的英语单词。包名统一使用单数形式但是类名如果有复数含义类名可以使用复数形式。正例应用工具类包名为com.alibaba.ei.kunlun.aap.util、类名为 MessageUtils此规则参考 spring 的 框架结构1. 包名统一使用小写这是 Java 包名的基础行业惯例核心原因有 2 点跨平台兼容Windows 系统的文件系统是 “大小写不敏感” 的比如Util和util会被识别为同一个文件夹而 Linux/Mac 是 “大小写敏感” 的。如果包名混用大小写如com.alibaba.Util在不同系统部署时可能出现 “找不到包” 的异常全小写可彻底规避这个问题。避免视觉混淆包名小写能和 “类名大驼峰” 形成鲜明区分如包utilvs 类MessageUtils阅读代码时可快速识别 “包” 和 “类”降低认知成本。2. 点分隔符之间有且仅有一个自然语义的英语单词“点.” 是包名的层级分隔符每个分隔符之间必须是单个、有完整语义的英文单词核心是避免 “语义堆砌” 导致的可读性下降✅ 正例com.alibaba.ei.kunlun.aap.util每个点分隔的com、alibaba、ei、kunlun、aap、util都是单个语义单词分别对应 “顶级域名、公司名、业务线、产品、模块、功能”层级和语义清晰。❌ 反例com.alibaba.userinfo把user用户和info信息拼接成一个单词语义边界模糊无法快速识别是 “用户模块” 还是 “用户信息模块”com.alibaba.user_info用下划线分隔违背 “仅单个单词” 的规则且下划线在包名中无语义价值com.alibaba.UserInfo混用大写违背 “包名小写” 规则。3. 包名统一使用单数形式包名代表 “一个功能模块 / 业务领域”是集合概念单数形式更符合英文语义和行业惯例✅ 正例util工具包、service服务包、model模型包、dao数据访问包❌ 反例utils、services、models、daos。原因包是 “容纳某类功能代码的容器”比如util包是 “工具功能的容器”而非 “多个工具”单数形式更贴合 “模块 / 领域” 的语义且 Spring、MyBatis 等主流框架的包名均采用单数如org.springframework.util、org.mybatis.dao统一风格可降低协作成本。类名复数规则解析“类名如果有复数含义可使用复数形式”核心是让类名贴合语义本质而非机械遵循 “单数”如MessageUtils“Utils” 是 “Utility工具” 的复数代表这个类包含多个消息相关的工具方法复数形式能直观体现 “工具集合” 的语义Users如果类用于处理 “多个用户” 的逻辑如用户列表、批量用户操作复数形式比User更清晰Orders同理用于批量订单处理的类复数更贴合语义11.避免在子父类的成员变量之间、或者不同代码块的局部变量之间采用完全相同的命名使可理解性降低。说明子类、父类成员变量名相同即使是 public 类型的变量也能够通过编译另外局部变量在同一方法内的不同代码块中同名也是合法的这些情况都要避免。对于非 setter/getter 的参数名称也要避免与成 员变量名称相同。反例public class ConfusingName { public int stock; // 非 setter/getter 的参数名称不允许与本类成员变量同名 public void get(String alibaba) { if (condition) { final int money 666; // ... } for (int i 0; i 10; i) { // 在同一方法体中不允许与其它代码块中的 money 命名相同 final int money 15978; // ... } } } class Son extends ConfusingName { // 不允许与父类的成员变量名称相同 public int stock; }场景 1子父类成员变量同名问题危害多人维护时新增 / 修改父类name变量时可能忽略子类有同名变量导致逻辑不一致若代码中忘记加super会误操作子类变量引发隐蔽的业务 bug阅读代码时需反复确认变量归属降低可理解性。场景 2不同代码块的局部变量同名视觉上的 “同名” 会误导开发者判断变量的修改范围比如误以为内部代码块的count修改了外部的count代码块嵌套越深、长度越长越容易忘记 “内部变量是新变量”导致逻辑判断错误。场景 3非 setter/getter 的参数名与成员变量同名问题本质规范特别说明 “setter/getter 例外”—— 因为setName(String name)是行业通用惯例所有开发者都能理解但业务方法 / 工具方法的参数名若与成员变量同名方法内直接使用变量名时会优先取参数值若忘记加this修饰会误操作参数而非成员变量引发 bug。反例public class UserService { // 成员变量 private String userName 默认名称; // 错误非setter方法的参数名与成员变量同名 public void updateUser(String userName) { // 开发者以为是给成员变量赋值实际是给参数本身赋值无意义 userName 新名称; // 正确赋值需加thisthis.userName userName; 但极易忘记 System.out.println(userName); // 输出“新名称”但成员变量仍为“默认名称” } }12.杜绝完全不规范的缩写避免望文不知义。反例AbstractClass“缩写”成 AbsClasscondition“缩写”成 condiFunction 缩写”成 Fu此类随意缩写严重降低了代码的可阅读性。13.接口和实现类的命名对于 Service 和 DAO 类基于 SOA 的理念暴露出来的服务一定是接口内部的实现类用Impl 的后缀与接口区别。正例CacheServiceImpl 实现 CacheService 接口核心逻辑解析这一规则的本质是贯彻 “接口与实现分离” 的设计思想贴合 SOA 面向服务架构通过统一的命名约定让接口服务契约和实现类具体逻辑形成清晰的视觉区分同时提升代码的可读性、扩展性和团队协作效率。1. 最核心贴合 SOA面向服务架构的设计理念SOA 的核心是 “服务接口化”—— 将系统的功能封装为 “服务”对外仅暴露接口定义 “服务能做什么”即服务契约而实现类定义 “服务具体怎么做”隐藏在内部。接口如CacheService是对外的 “服务约定”规定了方法名、入参、返回值不包含任何业务逻辑是跨模块 / 跨系统协作的 “契约”实现类如CacheServiceImpl是契约的具体落地包含缓存操作的实际逻辑如操作 Redis、本地缓存等属于内部实现不对外暴露。Impl后缀的核心作用是明确标识 “这是接口的实现类”而非新的接口 / 工具类完全契合 SOA “接口与实现分离” 的核心要求。2.Impl后缀提供强视觉标识让接口和实现类一目了然提升代码可读性和查找效率3.便于扩展多实现类统一的命名规则降低团队协作成本同时适配 Spring 等主流框架的使用习惯。