规范文档


JAVA编码规范

<h1>Java编码规范</h1> <h2>1 说明</h2> <h3>1.1 范围</h3> <p>本规范规定了使用Java语言时排版、注释、命名、编码的规则和建议。<br /> 本规范适用于使用Java语言成的产品和项目。 </p> <h3>1.2 术语和定义</h3> <ul> <li>规则:必须遵守</li> <li>建议:有充足的理由时可不遵守,但必须优先考虑</li> <li>格式:对规范格式的说明或模板</li> <li>说明:对规范或建议进行的必要解释</li> <li>示例:对规范或建议从正反两方面给出的例子</li> <li>补充:一些实践技巧或额外的说明 </li> </ul> <h2>2 排版规则</h2> <h3>2.1 编码</h3> <p><strong>规 则:IDE的text file encoding设置为UTF-8。</strong><br /> <strong>规 则:IDE中文件的换行符使用Unix格式,不要使用windows格式。</strong> </p> <h3>2.2 页宽</h3> <p><strong>规 则:编辑器列宽应设置为100列</strong><br /> <strong>说 明:</strong> 当一行代码的长度过长时,为了阅读方便,应该换行展示。但因为每个人的字体设置,屏幕大小有所不同,因此需要统一列宽为100列。<br /> <strong>补 充:</strong> </p> <h3>2.3 换行</h3> <p><strong>规 则:第二行相对第一行缩进4个空格,从第三行开始,不再缩进,而是与第二行保持同级。</strong><br /> <strong>规 则:运算符、方法调用的点符号与下文一起换行。</strong><br /> <strong>规 则:在多个参数超长时,逗号后换行。</strong><br /> <strong>示 例:</strong> </p> <pre><code class="language-java">//符合规范 StringBuffer sb = new StringBuffer(); //超过100个字符的时候,换行缩进4个空格,并且方法钱的点符号一起换行 sb.append(&amp;quot;wan&amp;quot;).append(&amp;quot;fang&amp;quot;)... .append(&amp;quot;shu&amp;quot;)... .append(&amp;quot;ju&amp;quot;)... .append(&amp;quot;gu&amp;quot;); //在逗号后换行 method(arg1, arg2, arg3, ...argx, argx1)</code></pre> <h3>2.4 缩进</h3> <p><strong>规 则:程序块需要采用缩进风格编写,缩进为4个空格。</strong><br /> <strong>说 明:</strong> 不同的编辑工具会导致Tab字符的宽度不统一,在编码时应注意其可能造成的问题。<br /> <strong>补 充:</strong> </p> <h3>2.5 空行</h3> <p><strong>规则:独立的程序块与变量声明之间加空行分割</strong> <strong>示 例:</strong> </p> <pre><code class="language-java">//不符合规范 if(log.getLevel() &amp;lt; LogConfig.getRecordLevel()){ return; } LogWriter writer; int index;</code></pre> <pre><code class="language-java">//符合规范 if(log.getLevel() &amp;lt; LogConfig.getRecordLevel()){ return; } LogWriter writer; int index; </code></pre> <h3>2.6 大括号</h3> <p><strong>规 则:使用大括号(即使是可选的)</strong><br /> <strong>说 明:</strong> 大括号与if, else, for, do, while即使只有一条语句或是空,也应该把大括号写上。<br /> <strong>示 例:</strong> </p> <pre><code class="language-java">//不符合规范的 if(writeToFile) writeFileThread.interrupt();</code></pre> <pre><code class="language-java">//符合规范的 if(writeToFile){ writeFileThread.interrupt(); }</code></pre> <p><strong>规 则:对于非空块和块状结构,大括号遵循Kernighan和Ritchie风格(紧凑风格)。</strong><br /> <strong>说 明:</strong></p> <ul> <li>左大括号前不换行 </li> <li>左大括号后换行</li> <li>右大括号前换行</li> <li>如果右大括号是一个语句、函数体或类的终止,则右大括号后换行; 否则不换行。例如,如果右大括号后面是else或逗号,则不换行 </li> </ul> <p><strong>示 例:</strong> </p> <pre><code class="language-java">//不符合规范 if(isOk) { someThing(); } else { otherThing(); }</code></pre> <pre><code class="language-java">//符合规范 if(isOk){ someThing(); }else{ otherThing(); }</code></pre> <p><strong>补 充:</strong><br /> Kernighan和Ritchie风格指的是,Kernighan和Ritchie的《C Programming Language》一书中约定的“大括号放在同一行”规则。这种编码风格比较紧凑,也是Java官方和Google等诸多主流公司遵循的编码风格。 </p> <p><strong>建 议:空块可以简洁的写成{},除非它是多块语句的一部分。</strong><br /> <strong>说 明:</strong> 一个空的块状结构里什么也不包含,大括号可以简洁地写成{},不需要换行。例外:如果它是一个多块语句的一部分(if/else 或 try/catch/finally) ,即使大括号内没内容,右大括号也要换行。<br /> <strong>示 例:</strong> </p> <pre><code class="language-java">void doNothing() {}</code></pre> <h3>2.7 小括号</h3> <p><strong>规 则:用小括号来限定计算优先级</strong><br /> <strong>说 明:</strong> 没有理由假设代码的阅读者能够清晰的记住整个Java运算符优先级表。</p> <h3>2.8 空格</h3> <p><strong>规 则:函数参数在“,”后需要加空格。</strong><br /> <strong>规 则:各种双目操作符,比如“=”,“&lt;”等,前后都要加空格。</strong><br /> <strong>规 则:if, while等关键字后面需要有空格。</strong><br /> <strong>补 充:</strong> 基本上Eclipse的自动格式化功能,就能保证这些空格的正确使用。</p> <h3>2.9 TODO</h3> <p><strong>规 则:TODO用于任务标记,要避免出现无用的TODO标记</strong><br /> <strong>说 明:</strong> 自动生成代码中如果有TODO标记,请根据需要编写注释或删除TODO标记,避免产生无用的TODO,影响他人跟踪任务。</p> <h3>2.10 import</h3> <p><strong>规 则:import不要使用通配符</strong><br /> <strong>说 明:</strong> 不要出现类似这样的import语句:import java.util.*。使用通配符会造成歧义,及不可预期的冲突或bug。程序应保持清晰、易懂、无歧义。 </p> <p><strong>规 则:import不要引用不需要的包</strong> </p> <h3>2.11 变量</h3> <p><strong>规 则:每次只声明一个变量</strong><br /> <strong>说 明:</strong> 不要使用组合声明(int a,b;),减少歧义性,增强可读性 </p> <p><strong>规 则:需要时才声明,并尽快进行初始化</strong> </p> <p><strong>规 则:使用非C风格的数组声明</strong><br /> <strong>说 明:</strong> 使用String[] args,而非String args[] </p> <p><strong>建 议:谨慎的使用公共变量</strong><br /> <strong>说 明:</strong> 公共变量是增大模块间耦合的原因之一,应减少没必要的公共变量以降低模块间的耦合度。 </p> <h2>3 命名规范</h2> <p><strong>规 则:命名应尽可能做到见名知意,力求语义表达清晰完整。</strong><br /> <strong>规 则:代码中的命名均不能以下划线或美元符号开始,也不能以下划线或美元符号结束。</strong><br /> <strong>规 则:代码中的命名严禁使用拼音与英文混合的方式,更不允许直接使用中文的方式。</strong> </p> <h3>3.1 package</h3> <p><strong>规 则:包名均采用小写</strong><br /> <strong>建 议:包名一般为一个单词</strong> </p> <p><strong>规 则:内部包名规则一般为com.部门名称/站点域名.产品名/项目名.模块名,通用包放在com.wanfangdata下</strong><br /> <strong>说 明:</strong> 由于历史遗留原因,部分内部包名格式为:部门名称.产品名/项目名.模块名。原则上,新建的包不要用此命名规则,但暂时也不修改此规则的包名 </p> <h3>3.2 Class</h3> <p><strong>规 则:类的命名应该都是名词</strong><br /> <strong>规 则:类名第一个字母要为大写,其他每个单词的第一个字母为大写(UpperCamelCase)</strong><br /> <strong>规 则:类名要用完整的单词,除非是被公认的单词缩写</strong><br /> <strong>规 则:抽象类命名应以Abstract为开头</strong><br /> <strong>规 则:异常类命名使用Exception结尾</strong> <strong>规 则:测试类命名以它要测试的类名称开始,以Test结尾</strong></p> <p><strong>建 议:如果使用了设计模式,建议在类(接口)命名中体现出具体的设计模式</strong> <strong>建 议:枚举类名以Enum后缀结束,美剧成员名称需要全部大写,单词间用下划线分隔。</strong><br /> <strong>示 例:</strong></p> <pre><code class="language-java">public class BalanceLimitAccountHandler; public interface SqlSessionFactory; public class LoginProxy;</code></pre> <h3>3.3 Interface</h3> <p><strong>规 则:接口名的命名应该是名词或形容词</strong><br /> <strong>规 则:接口名应以大写的I开头,其他单词第一个字母都要大写(UpperCamelCase)</strong><br /> <strong>规 则:接口名要用完整的单词,除非是被公认的单词缩写</strong><br /> <strong>建 议:接口类中的方法和属性不要加任何修饰符好(public也不要加)。</strong></p> <h3>3.4 方法命名</h3> <p><strong>规 则:方法名应以动词或惯用短语描述</strong><br /> <strong>规 则:方法名第一个字母都要小写,其他每个单词第一个字母都要大写(lowerCamelCase)</strong> </p> <p><strong>建 议:方法名中不要加入对象名字,可能会带来误解。</strong><br /> <strong>说 明:</strong> 因为对象本身已经包含在调用语句中了</p> <h3>3.5 变量</h3> <p><strong>规 则:应避免用单个字符命名变量</strong><br /> <strong>规 则:代码中严禁使用拼音与英文混合的方式,优先使用英文而非拼音</strong> </p> <p><strong>规 则:参数名第一个字母使用小写,其他每个单词第一个字母大写(lowerCamelCase)</strong> </p> <p><strong>规 则:常量名应该为名词或名词短语</strong><br /> <strong>规 则:常量名每一个字母都应为大写,单词之间用“_”分开。</strong><br /> <strong>规 则:不允许出现任何魔法值(未经定义的常量)直接出现在代码中。</strong><br /> <strong>建 议:不要使用一个常量类维护所有常量,应该按常量功能进行归类,分开维护。</strong> </p> <p><strong>规 则:long或者Long初始赋值时,必须使用大写的L,不能是小写的l,小写容易跟数字1混淆,造成误解。</strong> </p> <p><strong>规 则:局部变量名第一个字母使用小写,其他每个单词第一个字母大写(lowerCamelCase)。</strong><br /> <strong>规 则:局部变量名可以更宽松的使用缩写,但除了临时变量和循环变量应避免单字符命名。</strong> </p> <p><strong>规 则:POJO类中布尔类型的变量,都不要加is,否则部分框架解析会引起序列化错误。(参考阿里java规范)</strong><br /> <strong>说 明:</strong><br /> 定义为基本数据类型Boolean isSuccess;的属性,它的方法也是isSuccess(),RPC框架在反向解析的时候,“以为”对应的属性名称是success,导致属性获取不到,进而抛出异常。</p> <h2>4 注释规范</h2> <h3>4.1 文档注释</h3> <p><strong>规 则:一般情况下,源程序有效注释量必须在30%以上。</strong><br /> <strong>规 则:接口、Action方法、工具类的public方法等凡是提供给外界调用的方法都必须添加文档注释。</strong><br /> <strong>规 则:文档注释用于描述Java的类、接口、构造函数、方法,一级成员变量(field)。</strong> </p> <p><strong>规 则:类和接口的注释在 package 关键字之后,class 或者 interface 关键字之前。</strong><br /> <strong>规 则:类和接口的注释内容:类的注释主要是一句话功能简述、功能详细描述。</strong><br /> <strong>说 明:</strong> 可根据需要列出:版本号、生成日期、作者、内容、功能、与其它类的关系等。 如果一个类存在Bug,请如实说明这些Bug </p> <pre><code class="language-java">/** * 〈一句话功能简述〉 * 〈功能详细描述〉 * @author [作者] * @version [版本号, YYYY-MM-DD] * @see [相关类/方法] * @since [产品/模块版本] * @deprecated */</code></pre> <p><strong>示例:</strong> </p> <pre><code class="language-java">/** * LogManager 类集中控制对日志读写的操作。 * 全部为静态变量和静态方法,对外提供统一接口。分配对应日志类型的读写器, * 读取或写入符合条件的日志纪录。 * @author 张三,李四,王五 * @version 1.2, 2001-03-25 * @see LogIteraotor * @see BasicLog * @since CommonLog1.0 */</code></pre> <p><strong>规 则:类属性、公有和保护方法注释:写在类属性、公有和保护方法上面</strong><br /> <strong>规 则:成员变量使用文档注释,而不是单行注释或尾部注释</strong><br /> <strong>规 则:成员变量注释内容:成员变量的意义、目的、功能,可能被用到的地方</strong> </p> <p><strong>规 则:公有和保护方法注释内容:列出方法的一句话功能简述、功能详细描述、输入参数、输出参数、返回值、违例等</strong><br /> <strong>说明:</strong></p> <pre><code class="language-java">/** * 〈一句话功能简述〉 * 〈功能详细描述〉 * @param [参数1] [参数1说明] * @param [参数2] [参数2说明] * @return [返回类型说明] * @exception/throws [违例类型] [违例说明] * @see [类、类#方法、类#成员] * @deprecated */</code></pre> <p><strong>示 例:</strong></p> <pre><code class="language-java">/** * 根据日志类型和时间读取日志。 * 分配对应日志类型的LogReader, 指定类型、查询时间段、条件和反复器缓冲数, * 读取日志记录。查询条件为null或0表示无限制,反复器缓冲数为0读不到日志。 * 查询时间为左包含原则,即 [startTime, endTime) 。 * @param logTypeName 日志类型名(在配置文件中定义的) * @param startTime 查询日志的开始时间 * @param endTime 查询日志的结束时间 * @param logLevel 查询日志的级别 * @param userName 查询该用户的日志 * @param bufferNum 日志反复器缓冲记录数 * @return 结果集,日志反复器 * @since CommonLog1.0 */ public static LogIterator read(String logType, Date startTime, Date endTime, int logLevel, String userName, int bufferNum)</code></pre> <h3>4.2 块注释</h3> <p><strong>规 则:块注释用来为文件、方法、数据结构和算法进行描述或是用来划分文件的模块</strong><br /> <strong>规 则:块注释一般放在每个文件的开始或是每个模块、方法的前面,也可能放在方法之内</strong><br /> <strong>规 则:在块注释前应该有一个空行,以便同其他代码进行分割</strong> </p> <h3>4.3 单行注释</h3> <p><strong>规 则:简短的注释可以只用一行来说明,并与后面的代码进行相同的缩进</strong><br /> <strong>规 则:单行注释如果一行写不下,就应该考虑使用块注释</strong><br /> <strong>规 则:在单行注释前应该有一个空行,以便痛其他代码进行分割</strong><br /> <strong>规 则:非常短的注释可以跟被说明的代码放在同一行,以尾部注释的形式出现</strong> </p> <h3>4.4 注意事项</h3> <p><strong>规 则:注释必须与代码同步更新</strong><br /> <strong>建 议:应避免注释中提供代码中已清晰表达出来的重复信息</strong><br /> <strong>建 议:当要写非文档注释的时候,应考虑下是否可以将代码写的更清晰易懂</strong><br /> <strong>说 明:</strong> 过多的非文档注释,往往反映出代码的低质量<br /> <strong>建 议:TODO与FIXME注释格式建议包含(标记人,标记时间,[预计处理时间])</strong> </p> <h2>5 编程技巧</h2> <h3>5.1 类</h3> <p><strong>规 则:明确类的功能,精确(而非近似)地实现类的设计,一个类仅实现一组相近的功能</strong><br /> <strong>说 明:</strong> 划分类的时候,应该尽量把逻辑处理、数据和显示分离,实现类功能的单一性<br /> <strong>示 例:</strong> 数据类不能包含数据处理的逻辑,通信类不能包含显示处理的逻辑 </p> <p><strong>规 则:所有的数据类必须重载toString() 方法,返回该类有意义的内容</strong><br /> <strong>说 明:</strong> 如果父类中已经实现了较为合理的toString()方法,子类可以继承而不必重写 </p> <p><strong>规 则:只要重写equals,就必须重写hashCode。</strong><br /> <strong>规 则:因为Set存储的是不重复的对象,依据hashCode和equals进行判断,所以Set存储的对象必须重写这两个方法。</strong><br /> <strong>规 则:如果自定义对象做为Map的键,那么必须重写hashCode和equals。</strong> </p> <p><strong>建 议:@Override能用则用</strong><br /> <strong>说 明:</strong> 只要是合法的,就把@Override注解用上。<br /> <strong>补 充:</strong> 参考自谷歌编码规范 </p> <h3>5.2 方法</h3> <p><strong>规 则:参数个数&gt;4个时抽取参数类</strong><br /> <strong>建 议:参数列表中请尽量不取用true、false类参数,避免因为调用者不明确导致的问题</strong> </p> <p><strong>建 议:返回调用函数方应该知道的消息,慎用void</strong><br /> <strong>建 议:返回空的集合时使用Collections.empty方法,不要直接返回null</strong> </p> <p><strong>规 则:每个方法不得超过100行</strong><br /> <strong>建 议:超过50行的代码建议考虑重构</strong> </p> <p><strong>规 则:方法不得包含隐式功能</strong><br /> <strong>说 明:</strong> 如:getIdsFromList(List modelList)仅应该执行从list获取id的操作,而不应该对list有修改 </p> <p><strong>规 则:避免使用不易理解的数字,用有意义的标识来替代</strong><br /> <strong>规 则:涉及物理状态或者含有物理意义的常量,不应直接使用数字,必须用有意义的静态变量来代替</strong> </p> <h3>5.3 控制语句</h3> <p><strong>规 则:在一个switch块内,都必须包含一个default语句并且放在最后,即使它什么代码也没有</strong><br /> <strong>规 则:在if/else/for/while/do语句中必须使用大括号,即使只有一行代码,避免使用下面的形式:if (condition) statements;</strong> </p> <p><strong>规 则:尽量少用else</strong><br /> <strong>示 例:</strong> </p> <pre><code class="language-java">//不符合规范 if(condition) { ... return obj; } //接着写else的业务逻辑代码</code></pre> <h3>5.4 数据校验</h3> <p><strong>建 议:方法中需要进行参数校验的场景</strong> </p> <ul> <li>调用频次低的方法</li> <li>执行时间开销很大的方法,参数校验时间几乎可以忽略不计,但如果因为参数错误导致中间执行回退,或者错误,那得不偿失。</li> <li>需要极高稳定性和可用性的方法</li> <li>对外提供的开放接口,不管是RPC/API/HTTP接口</li> <li>敏感权限入口</li> </ul> <p><strong>建 议:方法中不需要参数校验的场景</strong> </p> <ul> <li>极有可能被循环调用的方法,不建议对参数进行校验。但在方法说明里必须注明外部参数检查。</li> <li>底层的方法调用频度都比较高,一般不校验。(参数错误不太可能到底层才会暴露问题)</li> <li>被声明成private只会被自己代码所调用的方法。 <h2>Creators</h2> <p><a href="https://github.com/meibaorui">梅葆瑞</a><br /> [李辉]()<br /> <a href="https://github.com/pizirui">张锐</a> </p></li> </ul>

页面列表

ITEM_HTML