简洁清爽的代码风格应该是大多数工程师所期待的。在工作中笔者常常因为起名字而纠结,夸张点可以说是编程 5 分钟,命名两小时!究竟为什么命名成为了工作中的拦路虎。
每个公司都有不同的标准,目的是为了保持统一,减少沟通成本,提升团队研发效能。所以本文中是笔者结合阿里巴巴开发规范,以及工作中的见闻针对 Java 领域相关命名进行整理和总结,仅供参考。
一,Java 中的命名规范
好的命名能体现出代码的特征,含义或者是用途,让阅读者可以根据名称的含义快速厘清程序的脉络。不同语言中采用的命名形式大相径庭,Java 中常用到的命名形式共有三种,既首字母大写的 UpperCamelCase,首字母小写的 lowerCamelCase 以及全部大写的并用下划线分割单词的 UPPER_CAMEL_UNSER_SCORE。通常约定,类一般采用大驼峰命名,方法和局部变量使用小驼峰命名,而大写下划线命名通常是常量和枚举中使用。
二,包命名
包名统一使用小写,点分隔符之间有且仅有一个自然语义的英文单词或者多个单词自然连接到一块(如 springframework,deepspace 不需要使用任何分割)。包名统一使用单数形式,如果类命有复数含义,则可以使用复数形式。
包名的构成可以分为以下几四部分【前缀】 【发起者名】【项目名】【模块名】。常见的前缀可以分为以下几种:
三,类命名
类名使用大驼峰命名形式,类命通常时名词或名词短语,接口名除了用名词和名词短语以外,还可以使用形容词或形容词短语,如 Cloneable,Callable 等,表示实现该接口的类有某种功能或能力。对于测试类则以它要测试的类开头,以 Test 结尾,如 HashMapTest。
对于一些特殊特有名词缩写也可以使用全大写命名,比如 XMLHttpRequest,不过笔者认为缩写三个字母以内都大写,超过三个字母则按照要给单词算。这个没有标准如阿里巴巴中 fastjson 用 JSONObject 作为类命,而 google 则使用 JsonObjectRequest 命名,对于这种特殊的缩写,原则是统一就好。
四,方法
方法命名采用小驼峰的形式,首字小写,往后的每个单词首字母都要大写。和类名不同的是,方法命名一般为动词或动词短语,与参数或参数名共同组成动宾短语,即动词 + 名词。一个好的函数名一般能通过名字直接获知该函数实现什么样的功能。
4.1 返回真伪值的方法
注:Prefix-前缀,Suffix-后缀,Alone-单独使用
4.2 用来检查的方法
4.3 按需求才执行的方法
4.4 异步相关方法
4.5 回调方法
4.6 操作对象生命周期的方法
4.7 与集合操作相关的方法
4.8 与数据相关的方法
4.9 成对出现的动词
五,变量&常量命名
5.1 变量命名
变量是指在程序运行中可以改变其值的量,包括成员变量和局部变量。变量名由多单词组成时,第一个单词的首字母小写,其后单词的首字母大写,俗称骆驼式命名法(也称驼峰命名法),如 computedValues,index、变量命名时,尽量简短且能清楚的表达变量的作用,命名体现具体的业务含义即可。
变量名不应以下划线或美元符号开头,尽管这在语法上是允许的。变量名应简短且富于描述。变量名的选用应该易于记忆,即,能够指出其用途。尽量避免单个字符的变量名,除非是一次性的临时变量。pojo 中的布尔变量,都不要加 is(数据库中的布尔字段全都要加 is_ 前缀)。
5.2 常量命名
常量命名 CONSTANT_CASE,一般采用全部大写(作为方法参数时除外),单词间用下划线分割。那么什么是常量呢?
常量是在作用域内保持不变的值,一般使用 final 进行修饰。一般分为三种,全局常量(public static final 修饰),类内常量(private static final 修饰)以及局部常量(方法内,或者参数中的常量),局部常量比较特殊,通常采用小驼峰命名即可。
/** * 一个demo * * @author Jann Lee * @date 2019-12-07 00:25 **/public class HelloWorld { /** * 局部常量(正例) */ public static final long USER_MESSAGE_CACHE_EXPIRE_TIME = 3600; /** * 局部常量(反例,命名不清晰) */ public static final long MESSAGE_CACHE_TIME = 3600; /** * 全局常量 */ private static final String ERROR_MESSAGE = " error message"; /** * 成员变量 */ private int currentUserId; /** * 控制台打印 {@code message} 信息 * * @param message 消息体,局部常量 */ public void sayHello(final String message){ System.out.println("Hello world!"); }}
常量一般都有自己的业务含义,不要害怕长度过长而进行省略或者缩写。如,用户消息缓存过期时间的表示,那种方式更佳清晰,交给你来评判。
通用命名规则#
六,代码注解
6.1 注解的原则
好的命名增加代码阅读性,代码的命名往往有严格的限制。而注解不同,程序员往往可以自由发挥,单并不意味着可以为所欲为之胡作非为。优雅的注解通常要满足三要素。
- Nothing is strange 没有注解的代码对于阅读者非常不友好,哪怕代码写的在清除,阅读者至少从心理上会有抵触,更何况代码中往往有许多复杂的逻辑,所以一定要写注解,不仅要记录代码的逻辑,还有说清楚修改的逻辑。
- Less is more 从代码维护角度来讲,代码中的注解一定是精华中的精华。合理清晰的命名能让代码易于理解,对于逻辑简单且命名规范,能够清楚表达代码功能的代码不需要注解。滥用注解会增加额外的负担,更何况大部分都是废话。
// 根据id获取信息【废话注解】getMessageById(id)
Advance with the time 注解应该随着代码的变动而改变,注解表达的信息要与代码中完全一致。通常情况下修改代码后一定要修改注解。6.2 注解格式
注解大体上可以分为两种,一种是 javadoc 注解,另一种是简单注解。javadoc 注解可以生成 JavaAPI 为外部用户提供有效的支持 javadoc 注解通常在使用 IDEA,或者 Eclipse 等开发工具时都可以自动生成,也支持自定义的注解模板,仅需要对对应的字段进行解释。参与同一项目开发的同学,尽量设置成相同的注解模板。
a. 包注解
包注解在工作中往往比较特殊,通过包注解可以快速知悉当前包下代码是用来实现哪些功能,强烈建议工作中加上,尤其是对于一些比较复杂的包,包注解一般在包的根目录下,名称统一为 package-info.java。
/** * 落地也质量检测 * 1. 用来解决什么问题 * 对广告主投放的广告落地页进行性能检测,模拟不同的系统,如Android,IOS等; 模拟不同的网络:2G,3G,4G,wifi等 * * 2. 如何实现 * 基于chrome浏览器,用chromedriver驱动浏览器,设置对应的网络,OS参数,获取到浏览器返回结果。 * * 注意:网络环境配置信息{@link cn.mycookies.landingpagecheck.meta.NetWorkSpeedEnum}目前使用是常规速度,可以根据实际情况进行调整 * * @author cruder * @time 2019/12/7 20:3 下午 */package cn.mycookies.landingpagecheck;
b. 类注接
javadoc 注解中,每个类都必须有注解。
/*** Copyright (C), 2019-2020, Jann balabala...** 类的介绍:这是一个用来做什么事情的类,有哪些功能,用到的技术.....** @author 类创建者姓名 保持对齐* @date 创建日期 保持对齐* @version 版本号 保持对齐*/
c. 属性注解
在每个属性前面必须加上属性注释,通常有一下两种形式,至于怎么选择,你高兴就好,不过一个项目中要保持统一。
/** 提示信息 */private String userName;/** * 密码 */private String password;
d. 方法注释
在每个方法前面必须加上方法注释,对于方法中的每个参数,以及返回值都要有说明。
/** * 方法的详细说明,能干嘛,怎么实现的,注意事项... * * @param xxx 参数1的使用说明, 能否为null * @return 返回结果的说明, 不同情况下会返回怎样的结果 * @throws 异常类型 注明从此类方法中抛出异常的说明 */
e. 构造方法注释
在每个构造方法前面必须加上注释,注释模板如下:
/** * 构造方法的详细说明 * * @param xxx 参数1的使用说明, 能否为null * @throws 异常类型 注明从此类方法中抛出异常的说明 */
而简单注解往往是需要工程师字节定义,在使用注解时应该注意一下几点:
- 枚举类的各个属性值都要使用注解,枚举可以理解为是常量,通常不会发生改变,通常会被在多个地方引用,对枚举的修改和添加属性通常会带来很大的影响。
- 保持排版整洁,不要使用行尾注释;双斜杠和星号之后要用 1 个空格分隔。
id = 1;// 反例:不要使用行尾注释//反例:换行符与注释之间没有缩进int age = 18;// 正例:姓名String name;/** * 1. 多行注释 * * 2. 对于不同的逻辑说明,可以用空行分隔 */
总结
无论是命名和注解,他们的目的都是为了让代码和工程师进行对话,增强代码的可读性,可维护性。优秀的代码往往能够见名知意,注解往往是对命名的补充和完善。命名太南了!