编码规范
来源:互联网 发布:礼仪培训网络课程 编辑:程序博客网 时间:2024/06/05 08:58
第一章概述
前言
代码相当于程序的基石,一行行代码都是程序员的心血经过日日夜夜凝结而成的。它不仅仅是一行一行的字母+文字,它是程序员思想和经验的总结;编码规范只是大家在程序范围内达成一致的约定,这样大家的代码就可以互相看懂,维护起来更加容易,思想更畅快的交流,经验更快的得到传播。代码规范不是限制程序员的个性,应该知道,不遵守规范的个性的代码并不代表程序员的性格,并不能张扬个性。个性应该体现在用更简单、更优雅、更易读、更易理解以及算法实现效率更高等方面。
可读性,可理解性是代码的重要方面,本规范主要围绕如何去产生规范易读的代码。另外,它也保证了大家对同一代码段使用共同的语言进行描述。
术语
匈牙利命名法(Hungariannotation) 通过在变量名前面加上相应的小写字母的符号标识作为前缀,标识出变量的作用域,类型等。这些符号可以多个同时使用,顺序是先m_(成员变量),再指针,再简单数据类型,再其他。
例如:m_lpszStr,表示指向一个以0字符结尾的字符串的长指针成员变量。
骆驼命名法(Camel) 混合使用大小写字母来构成变量和函数的名字
例如:person, orderDetail, oilTank
帕斯卡命名法(Pascal) 与骆驼命名法类似,所有单词第一个字母大写,其它字母小写
例如:OilLevel, CustomerName
约束
没有一个规范可以到处适用,也不可能无所不包。
- 本规范并非完全强制性规范,对于任何违背本规范但能提高代码可读性的措施,都可以采用。
- 本规范第 3,4,5 章为强制性规范,其它章节为建议规范。如违背本条,请参考第一条。
第二章一般规则
- 所有包,类,接口,方法,属性,变量,参数均使用英文单词进行命名,具体细节请参见命名规范一章。
- 命名包,类,接口,方法以及变量时,尽量使用贴近问题域的表意丰富的名称。
- 修改源代码时,应尽量保持与所修改系统的编码风格保持一致。修改时,请注释掉修改的内容,并注明修改的时间及原因。
- 所有包名使用必须使用com.alibaba前缀,所有项目使用com.alibaba.aliai.[project name], project name 是项目的开发代号或缩写。
第三章格式规范
- 包的导入应该按照相关性进行分组。
importjava.io.IOException;
importjava.net.URL;
importjava.rmi.RmiServer;
importjava.rmi.server.Server;
importjavax.swing.JPanel;
importjavax.swing.event.ActionEvent;
importorg.linux.apache.server.SoapServer;
- 只导入明确需要的类,这样只要看导入列表,就可以知道该类依赖于哪些类和接口,保证可读性。
importjava.util.List; // 避免: importjava.util.*
importjava.util.Arraylist;
importjava.util.HashSet;
- 类和接口中元素的布局顺序。
- 类和接口的文档描述
- 类和接口的声明
- 类的静态变量,按照 public,protected,package,private 的顺序。
- 实例变量,按照 public,protected,package,private 的顺序。
- 类的方法,无固定顺序。
- 方法修饰关键字定义顺序_
<public, protected, private> staticabstractsynchronized
unuaual finalnativemethodName
注意访问标示符一定要在最前面。
publicstaticdoublesquare(doublea);
//避免: static public double square(double a);
- 变量声明,请使用骆驼命名法进行命名,不要在一行声明多个变量。
//推荐
intlevel;
intsize;
//避免
intlevel, size;
- 数组指示符紧跟类型变量
int[] a = new int[20]; // 避免: int a[] = new int[20]
一个变量要代表独立的意思,不要在其生命周期赋予它不同的概念。
inttempValue;
tempValue = maxValue;
...
...
tempValue = minValue;
...
tempValue = anotherValue;
tempValue 在生命周期内表示了各种各样的意图,增加理解代码的难度。
应该为每个独立概念定义单独的变量:
inttempMaxValue;
inttempMinValue;
inttempAnotherValue;
- 仅仅循环控制变量才能出现在 for()循环中
sum = 0;
for(i = 0; i< 100; i++) \{
sum += value[i];
\}
//避免:
for(i = 0, sum = 0; i< 100; i++)\{
sum += value[i];
\}
- 循环变量应靠近循环体初始化
isDone = false
while(!isDone){
...
}
//避免
isDone = false;
...
...
while(!isDone){
...
}
- 避免长的布尔表达式,应换成多个更容易理解的表达式。
boolisFinished = (elementNo< 0) || (elementNo>maxElement);
boolisRepeatedEntry = elementNo == lastElement;
if(isFinished || isRepeatedEntry) {
...
}
// 避免
if((elementNo< 0) || (elementNo>maxElement)|| elementNo ==
lastElement) {
...
}
- 不要在条件语句中执行方法,以提高可读性
InputStream stream = File.open(fileName, "w");
if(stream != null) {
...
}
//避免
if(File.open(fileName, "w") != null)) {
...
}
- 代码缩进,应该使用 4 个空格为一个单位进行缩进。
publicString invoke() throwsException {
....String profileKey = "invoke: ";
....try{
........UtilTimerStack.push(profileKey);
........if(executed) {
............test = true;
.......}
....catch{
....}
}
- 条件语句的主要形式,即使单条语句,也要使用括号括起来。
if(condition) \{
....statements;
\}
if(condition) \{
....statements;
\} else\{
....statements;
\}
if(condition) \{
....statements;
\} elseif(condition) \{
....statements;
\} else\{
....statements;
\}
- switch 语句的使用格式
switch(condition) {
caseABC :
....statements;
....//穿透,一定要做出注释
caseDEF :
....statements;
....break;
caseXYZ :
....statements;
....break;
....default:
....statements;
....break;
}
- 空格的使用
- 运算符两边应该各有一个空格。
- Java 保留字后面应跟随一个空格。
- 逗号后面应跟随一个空格。
- 冒号两个应各有一个空格。
- 分号后面应跟随一个空格。
- 空行的使用
- 文件头部注释、package 语句和import 语句之间。
- class 之间
- 方法之间
- 方法中,变量的申明和具体代码之间。
- 逻辑上相关的语句段之间
- 块注释和行注释的前面
▽ --- 代表空行
/**
*
*/
▽
packageXXX.XXX;
▽
importXXX.XXX.XXX.XXX;
▽
/**
*注释
*/
publicclassUserFileAccess {
▽
//
privateintmyObjId;
▽
/**
*
*/
publicUserFileAccess()
{ ・・・ \}
▽
/**
*
*/
publicvoidgetCtlInfo() {
intcount;
String msg;
▽
count = 100;
・・・
▽
//实现代码注释前空行
msg = "MESSAGE";
▽
count = dataCount;
if(count == 0) { ・・・ }
}
}
▽
/**
*
*/
privateclassUserFileRead {...}
- 逻辑上紧密相关的代码块应该用一个空行分开。
// Create a new identity matrix
Matrix4x4 matrix = newMatrix4x4();
// Precompute angles for efficiency
doublecosAngle = Math.cos(angle);
doublesinAngle = Math.sin(angle);
// Specify matrix as a rotation transformation
matrix.setElement(1, 1, cosAngle);
matrix.setElement(1, 2, sinAngle);
matrix.setElement(2, 1, -sinAngle);
matrix.setElement(2, 2, cosAngle);
// Apply rotation
transformation.multiply(matrix);
- 当对 if 语句中的条件进行折行时,应该使折行的条件语句相对主功能语句再行缩进4 个空格,以突出主要功能语句。
//使用这种缩进,突出主要功能语句。
if((condition1 && condition2)
........|| (condition3 && condition4)
........||!(condition5 && condition6))
{
....doSomethingAboutIt();}
//避免使用这种缩进,主功能语句不突出。
if((condition1 && condition2)
|| (condition3 && condition4)
||!(condition5 && condition6)) { ....doSomethingAboutIt();}
}
- 三元条件运算符
可以使用如下三种表达方式,条件要用括号括起来。
alpha = (aLongBooleanExpression) ? beta : gamma;
alpha = (aLongBooleanExpression) ? beta
: gamma;
alpha = (aLongBooleanExpression)
...............? beta
...............: gamma
第四章命名规范
一般命名规范
- 包名应该用小写字母,不要出现下划线等符号,名词用有意义的缩写或者英文单词。
示例:
//推荐
com.esse.business
java.lang.util
//避免
com.Esse-tech.buSiness
- 接口命名使用帕斯卡命名法形式的表示方式,使用名词组合。可以使用字母"I"加上帕斯卡命名法形式的表示方式
Query, DataAccess,ReportBuilder
IQuery, IDataAccess,IReportBuilder
- 所有类命名使用帕斯卡命名法表示方式,使用名词组合。
UserManagerImpl,ClassLoader,HttpHeaderResult
实现类如需要与接口做区分,那么在后面加上Impl,就像上面的UserManagerImpl
如果已经接口已经命名为I+帕斯卡命名法形式,对应实现类可以不用加上Impl
- 使用名词组合或形容词去命名一个接口,接口声明了一个对象能提供的服务,也描述了一个对象的能力。一般以"able"和"ible"作为后缀,代表了一种能力。
public interface Runnable{
....public void run();
}
public interface Accessible{
....public ContextgetContext();
}
- 变量名和参数名使用骆驼命名法进行表示。
userName, objectFactory, entrys, list
- 对于常量名,使用大写字母,并使用下划线做间隔。
MAX_TIMES, DEFAULT_NAME
- 程序中应该使用常量代替"25","100"等"魔法数"(过了很长一段时间后,你还记得它是做什么的吗?),如:
//推荐
if(times == MAX_TIMES) {
...
}
//避免
if(times == 25) {
...
}
- 这样做还有一个好处,当因为需要修改这些数字的时候,比如修改25 为30,我们只需要修改一处。
- 方法名应该使用动词开头,使用骆驼命名法表示方式,一般由动词+名词组成。
getName, initialize, addParameter, deleteUser
- 缩写字母也应该保持首字母大写
exportHtmlSource(); // 避免: exportHTMLSource();
openDvdPlayer(); // 避免: openDVDPlayer();
- 变量的名字应该和类型名称一致
void setTopic(Topic topic) // 避免: void setTopic(Topic value)
// 避免: void setTopic(Topic aTopic)
// 避免: void setTopic(Topic t)
voidconnect(Database database)
// 避免: void connect(Database db)
// 避免: void connect(Database oracleDB)
当同时定义多个属于同一个类的变量时,把类型作为实例的后缀,如:
Point startPoint;
Point centerPoint;
这样做是为了从实例名就可以推断它的类型名称。
- 根据变量的作用范围,作用范围大的应该使用长名称,作用范围大,表明变量的生命周期比较长,为了有助于理解,应尽量用长名称以表达变量的真实意图。反之,对于作用范围小,可以使用一些简化的名称,比如i,j,k 等,提高编程效率。
for(inti =0;i < times; i++)\{
...
\}
特殊命名规范
- 使用 get/set 对类属性进行访问,这是Java 社区的核心编码规范。使用 is 前缀表示一个布尔变量和方法。
isUsed, isEmpty,isVisible,isFinished
有时也可以使用 has,can,should:
booleanhasLicense();
booleancanEvaluate();
booleanshouldAbort = false;
- 在查询方法中应使用 find 作为前缀
vertex.findNearestVertex();
matrix.findSmallestElement();
node.findShortestPath(Node destinationNode);
- 使用 initialize 做为对象初始化的方法前缀,也可以简写为init
initializeFiles();
init();
initFontSet();
- 对于对象集合,变量名称应使用复数。
Collection<Point> points;
int[] values;
- 对于抽象类,应该使用 Abstract 前缀。
AbstractReportBuilder,AbstractBeanFactory
- 对于表示编号的变量,应加 No 后缀。
tableNo, userNo,employeeNo
- 常在一起使用的对称词汇,这些词汇一起使用,方法的表达意图自然可以互相推测和演绎。
get/set
add/remove
create/destroy
start/stop
insert/delete
increment/decrement
begin/end
first/last
up/down
min/max
next/previous
old/new
open/close
show/hide
suspend/resume
- 避免使用否定布尔变量
boolisError; // 避免: isNoError
boolisFound; // 避免: isNotFound
- 异常类应该使用 Exception 做为后缀。
AccessException, RuntimeException
- 缺省接口实现应该使用 Default 前缀
classDefaultTableCellRenderer implementsTableCellRenderer {
...
}
- 对于单例类(Singleton),应该使用getInstance方法得到单例。
classUnitManager {
privatefinalstaticUnitManager instance = newUnitManager();
privateUnitManager() {
...
}
publicstaticUnitManagergetInstance() {
returninstance;
}
}
- 对于工厂类,进行创建对象的方法,应该使用 new 前缀
classPointFactory {
publicPoint newPoint(...) {
...
}
}
第五章注释规范
概述
代码中为什么要包含注释?
- 别人要调用你的程序中的公共接口,对这部分进行文档描述,使别人能够正确而有效的使用它。
- 除了自己,别人要阅读和维护你的代码。为了使代码更容易维护,首先要使代码更易于理解,才能在理解的基础上进行维护。对这些代码进行文档描述,将使这个过程变得更加容易。
对代码进行注释,是在代码可读性的基础上,使用自然语言对代码所表达的意思进行阐述。这并不意味着说代码可以写的很烂,注释写的很详细,这不是好的方式。好的代码是自解释的,如果代码可读性很好,命名表意丰富,清晰,一般不需要特别多的注释。对于类,主要着重要描述它的职责,即它能干什么,对于复杂的算法实现,应该使用内部实现注释,说明算法的主要思路,对于长方法,要让阅读代码的人比较容易的明白方法实现的主要流程。反之,对于一看就懂的方法,则不需要进行注释,比如get/set方法。
一般原则
- 代码应该和注释保持同步,如果代码和注释不同步,则阅读代码的人会想,"到底是代码准确,还是注释准确呢?",换谁都会糊涂。
- 注释尽量简洁,尺度没有准确的定义,大部分人能明白即可,可以将自己的代码给同事看看。太简单的方法就不要注释了,比如上面提到的get/set 方法。
注释内容
/**
* Project: project Name
*
* File Created at 2009-11-17
* $Id$
*
* Copyright 2008 - 2009 Alibaba.com Croporation Limited.
* All rights reserved.
*
* This software is the confidential and proprietary information of
* Alibaba Company. ("Confidential Information"). You shall not
* disclose such Confidential Information and shall use it only in
* accordance with the terms of the license agreement you entered into
* with Alibaba.com.
*/
packagecom.alibaba.aliai.utils;
importjava.io.Serializable;
importjava.text.Format;
importjava.util.HashMap;
importjava.util.List;
importjava.util.Map;
importorg.apache.commons.logging.Log;
importorg.apache.commons.logging.LogFactory;
importcom.alibaba.aliai.site.service.IPostJobService;
importcom.caucho.hessian.client.HessianProxyFactory;
//① 代码的版权信息。
//② 类描述信息,描述类的主要职责和用处。
//③ 方法描述信息,描述方法是做什么的,如何调用,最好给出调用代码示例。
//④ JavaDoc tags ,用来生成Html形式的API 文档
//⑤ 内部实现注释,用于描述复杂的算法,长方法,从为什么要这么做角度去描述
//尽可能在类描述中加入代码调用示例,使用<pre></pre>标记,提示JavaDoc 工具不要改变格式.
/**
* DateFormat is an abstract class for date/time formatting formats and parses
* dates or time in a language-independent manner.
*
* <pre>
* myString = DateFormat.getDateInstance().format(myDate);
* </pre>
*
* <pre>
* DateFormatdf = DateFormat.getDateInstance();
* for (inti = 0; i<myDate.length; ++i) {
* output.println(df.format(myDate[i]) + "; ");
* }
* </pre>
*
* @see Format
* @see java.util.TimeZone
* @version 1.51 10/20/10
* @author author1,author2
*/
publicabstractclassTest extendsFormat {
//使用@deprecated废弃方法,不要删掉它。
/**
* @deprecated
*/
/*
* Get a default date/time formatter that uses the SHORT date and the time.
* public final static DateFormatgetInstance() { return
* getDateTimeInstance(SHORT, SHORT); }
*/
//包含代码调用示例
//使用行末注释对深层嵌套代码进行注释
publicvoidtest() {
for(inti = 0; i< 10; i++) {
for(intj = 0; j < 10; j++) {
while(1== 1) {
if(1== 2) {
switch(2) {
case1:
break;
case2:
break;
}// end switch
}//end if
}//end while
}//end for i
}//end for j
}
}
;陈春霞<wb-chunxia.chen@alibaba-inc.com>;霍丁<ding.huod@alibaba-inc.com>;李如<wb-liru1985@alibaba-inc.com>;刘艳欣<wb-liuyanxin.l@alibaba-inc.com>;杨冬<wb-yangdong@alibaba-inc.com>;陈传克<wb-chenchuanke@alibaba-inc.com>;王伟<wb-xuehunbense@alibaba-inc.com>;郭子球<wb-guoziqiu@alibaba-inc.com>;莫狄<diping.hdp@alibaba-inc.com>;
第六章编码原则
- 对于静态方法,应该使用类名去使用,不应该用实例去引用,主要是为了体现更多的语义。
Thread.sleep(1000);
//避免,无法体现sleep 是静态方法还是实例方法
thread.sleep(1000);
- 对一些基本数据类型和不太可能通过继承进行扩展的类,应声明为final,提高效率。
- 类和方法的粒度保持适中,保持类的规模尽量短小,职责单一。小类有很多好处,易于设计,易于测试,易于理解。同样方法也要尽量的小,每个方法尽量不要超出25 行。
- 开闭原则,软件应该对扩展开放,对修改开放。也就是说,应该在不修改以前源代码的基础上,改变程序的行为以适应新的需求。
- 里氏代换原则:假设有两个类,一个是基类 Base,一个是派生类Derived,如果一个方法可以接受基类对象b 的话:method1(Base b),同样,这个方法也应该接受派生类Derived 的对象d,而不影响方法的行为。里氏代换原则是继承复用的基石。
- 抽象依赖原则(稳定依赖原则)。应该依赖于抽象而不依赖与具体类,抽象的类和接口是稳定的,而具体类是易变的,如果依赖于具体类,代码就会非常脆弱,失去了灵活性。
- 接口隔离原则,一个类对另外一个类的依赖应该建立在最小的接口之上的。
- 单一职责原则,如果一个类有多于一种的职责,当需求变化时,类的职责就要发生变化,而因此就会引起引用该类的代码发生改变,职责越多,这个类就容易跟更多的类产生耦合关系,而且改变一个职责,可能会影响到另外一个职责的履行。
- 编写代码前,先编写注释(可以认为是伪代码),先想后写。
/*\*
\* 报表构建器,主要职责:
\* 1.创建拷贝报表模版
\* 2.填充报表数据
\* 3.构建报表
\* 4.画图处理
\*/
通过编写这些伪代码,可以起到理清思路的作用,这时候再编写代码,过程就非常流畅了,不会编一会儿,想一会儿,删掉代码,再重新编。- 编码规范
- 规范编码
- 编码规范
- 编码规范
- 编码规范
- 编码规范
- 编码规范
- 编码规范
- 编码规范
- 编码规范
- 编码规范
- 编码规范
- 编码规范
- 编码规范
- 编码规范
- 编码规范
- 编码规范
- 编码规范
- javascript中document学习
- 【笔面试】字符流和字节流的区别以及如何解决乱码问题
- java四舍五入与截取
- hadoop 日志文件自动清除设置
- nexus 6 remount失败问题
- 编码规范
- linux下导入、导出mysql数据库命令
- 如何创建和删除gerrit上的git tag
- 电商网站数据库设计好文章分享
- 查看 并发请求数及其TCP连接状态
- 蓝牙协议中HCI层的研究与开发
- 泛型
- QQ对接WEB网站的SDK下载
- 使用hiveF对sql语句的封装