1 简介
对于软件开发遵循统一的规范,有利于增强代码的可读性,同时防范错误,更好的发挥所使用的语言的优点,提高工作效率。所以我们制定此编程规范,指导公司的编码活动。本规范适用于公司各个使用Java作为开发语言的项目,作为源程序编写的规范,必须遵守。使用其他语言所编写的程序,比如Perl,在不和所使用的语言冲突的情况下,可以参考本规范的要求来编写源程序。
参考资料
文档名称 | 作者 | 发布日期 |
---|---|---|
《Rational Unified Process 2000》 | Rational Software Corporation | |
《C++编程规范》 | 摩托罗拉中国公司 | |
《高质量C语言编程》 | 林锐 | |
《Java编程规范》 | Sun |
2 文件和目录
2.1 文件使用统一而且通用的后缀名
- java程序的源文件: .java
- 二进制文件: .class
- AspectJ源文件: .aj
2.2 文件名要清晰、精炼、避免冲突
可以用公共前缀对文件分组,但是要防止名字过长和冗余信息过多。在一个项目中,遵循统一的文件名命名规则。
2.3 文件/目录名字字符集选择
- 只能使用以下字符集:[A-Za-z0-9_-]
- 包名只能用小写字符、数字和“.”。
- 类名第一个字符必须大写。
2.4 单个的文件建议不超过1000行
这项不作为强制条件执行,但一个类超过1000行,很有可能这个类的内聚性有问题。
2.5 单个的函数建议不超过100行,但一定不要超过200行
3 文件组织
每个Java源文件都包含一个单一的公共类或接口。若私有类和接口与一个公共类相关联,可以将它们和公共类放入同一个源文件(不建议)。公共类必须是这个文件中的第一个类或接口。 Java源文件还遵循以下规则:
- 文件头注释
- 包和引入语句
- 类和接口声明
3.1 文件头注释
参见注释里的文件头注释。
3.2 包和引入语句
在多数Java源文件中,第一个非注释行是包语句。在它之后可以跟引入语句。例如:
package java.awt;
import java.awt.peer.CanvasPeer;
3.3 类和接口说明
类/接口申明包括以下几部分:
- 1. 类/接口文档注释
- 2. 类或接口的声明
- 3. 类/接口实现的注释(该注释应包含任何有关整个类或接口的信息,而这些信息又不适合)
- 4. 类的(静态)变量
- 5. 实例变量
- 6. 构造器
- 7. 方法
3.4 变量申明的次序
变量申明的次序如下:
- 1. 先静态后实例变量
- 2. 先public后protected再private
4 排版
4.1 缩进
4个空格作为缩进排版的一个单位,缩进也可以使用TAB键。
4.2 在程序适当的地方加入空行
在以下地方应该是用空行分开:
- 1. 方法之间应该用空行分开;
- 2. 一组局部变量声明和代码之间用空行分开;
- 3. 用空行将代码按照逻辑片断划分;
- 4. 除非方法非常简单(如只有一两条语句),否则方法返回语句和其他语句用空行分开;
- 5. 每个类声明之后应该加入空行同其他代码分开;
4.3 换行
每一行不要超过120个字符,当一个表达式无法容纳在一行内时,可以依据如下规则分行书写:
- 1. 在一个逗号后面断开
- 2. 在一个操作符前面断开
- 3. 宁可选择较高级别(higher-level)的断开,而非较低级别(lower-level)的断开
- 4. 新的一行应该与上一行同一级别表达式的开头处对齐
- 5. 如果以上规则导致你的代码混乱或者使你的代码都堆挤在右边,那就代之以缩进4个空格。
示例:
以下是断开方法调用的一些例子:
foo.sum(longExpression1, longExpression2, longExpression3,
longExpression4, longExpression5);
var = foo.sum(longExpression1,
foo.sum(longExpression2,
longExpression3));
以下是两个断开算术表达式的例子。前者更好,因为断开处位于括号表达式的外边,这是个较高级别的断开,后者不建议采用。
longName1 = longName2 * (longName3 + longName4 - longName5)
+ 4 * longname6;
longName1 = longName2 * (longName3 + longName4
- longName5) + 4 * longname6;
以下是两个缩进方法声明的例子。前者是常规情形。后者若使用常规的缩进方式将会使第二行和第三行移得很靠右,所以代之以缩进4个空格。
//常规情形
public synchronized void invoke (int anArg, Object anotherArg,
String yetAnotherArg,
Object andStillAnother)
{
...
}
//缩进4个空格以免太靠右
public synchronized void invoke (int anArg, Object anotherArg,
String yetAnotherArg, Object andStillAnother)
{
...
}
4.4 一行只写一条语句
示例:
如下例子不符合规范:
rect.length = 0; rect.width = 0;
应如下书写:
rect.length = 0;
rect.width = 0;
4.5 if for do while等语句自占一行,其后无论执行语句多长,都应该使用{}
例外的情况是:如果存在多个if…else…语句并列,则else可以和if放在同一行。
示例:
如下的写法不合规范:
if (0 == a) return null;
应该这样写:
if (0 == a)
{
return null;
}
4.6 右大括号}要单独占一行,左大括号不作结强制规定,但在单个文件中要统一
右大括号要单独占一行,并且和它的控制语句有相同的缩进。但也有例外:
* 1. do-while循环中,}和while放在一行,应该按照以下格式书写:
do
{
i++;
} while (i < 100);
4.7 代码行之间应该留有适当的空格
代码行内应该适当的使用空格,具体地说来:
- 1. 关键字之后要留空格。象final、virtual、synchronized、case 等关键字之后至少要留一个空格,否则无法辨析关键字。象if、for、while 等关键字之后应留一个空格再跟左括号‘(’,以突出关键字。
- 2. 方法名之后不要留空格,紧跟左括号‘(’,以与关键字区别。
- 3. ‘(’向后紧跟,‘)’、‘,’、‘;’向前紧跟,紧跟处不留空格。
- 4. ‘,’之后要留空格,如function(int x, int y, int z)。如果‘;’不是一行的结束符号,其后要留空格,如for (initialization; condition; update)。
- 5. 值操作符、比较操作符、算术操作符、逻辑操作符、位域操作符,如“=”、“+=” “>=”、“<=”、“+”、“*”、“%”、“&&”、“||”、“<<”、“?”等二元操作符的前后应当加空格。
- 6. 一元操作符如“!”、“~”、“++”、“--”等前后都不加空格。
- 7. 象“[]”、“.”这类操作符前后不加空格。
示例,应该按照以下的格式书写:
void foo()
{
//…
}
或者:
if (0 == i)
{
//…
}
或者:
foo.bar
或者
foo[bar]
或者:
i++;
!i;
或者
i += 9;
a * b;
等等
5 命名规范
5.1 命名基本规范
命名应该遵守以下基本原则:
- 1. 命名要简单清楚,避免使用引起误解的词汇,避免使用模糊的缩写,长度不要超过25个字符
- 2. 命名必须使用英文单词,不能使用汉语拼音
- 3. 命名用可发音的名字
- 4. 选择通用词汇并且贯穿始终
- 5. 命名要通俗易懂
另外,命名还应该做到:
- 1. Package 的名字应该都是由一个全部小写单词组成。
- 2. Class 的名字必须由大写字母开头而其他字母都小写的单词组成
- 3. 变量的名字必须用一个全部小写的单词开头。后面的单词用大写字母开头,其余都小写。
- 4. 参数的名字必须和变量的命名规范一致。
- 5. 数组应该总是用下面的方式来命名:
byte[] buffer;
而不是:
byte buffer[];
- 6. 使用有意义的参数命名,如果可能的话,使用和要赋值的字段一样的名字:
setCounter(int count)
{
this. count = count;
}
5.2 类名采用每个单词首字母大写的方式
对于首字母缩写词如HTTP,把它同普通单词一样处理即仅有第一个H大写,其余字母小写。
5.3 包的命名格式采用utn.xxx开头
所有包的命名必须以utn.xxx开头,xxx代表项目或产品的简称。
5.4 常量、静态变量名采用全大写的方式,每个单词间用下划线分隔
这里的常量一般指类里用final static 修饰的成员变量。
5.5 变量名和方法名第一个单词的首字母小写,其余每个单词的首字母大写,首字母以外的字母全部小写
对于首字母缩写词如HTTP,把它同普通单词一样处理即仅有第一个H大写,其余字母小写。
6 注释
6.1 确保注释是完善你的代码而不是重复它
注释不应该包含代码本身显而易见的信息,而应该给出其他有用的信息。不仅要说明程序作了什么,还应该说明原因。
6.2 用中文或者英文注释代码
如果我们使用的开发平台支持中文,则尽可能的使用中文;否则使用流利的英语。
6.3 注释用词要精确,不能有二义性
人与人交流最大的问题就是误解。你以为他们看懂了你的注释或者他们认为自己看懂了你的注释,实际上往往并非如此,所以对于注释要和代码一样的进行审查。
6.4 注释中的术语要通用
6.5 注释应该和代码同步更新
6.6 禁止使用行尾注释
禁止采用行尾注释方法
int timeLength; //表示经历时间的长度
使用以下的注释方法
//表示经历时间的长度
int timeLength;
或者这个变量非常重要,可以使用文档注释:
/**
* 表示经历时间的长度
*/
int timeLength;
6.7 注释不要嵌套
6.8 使用文档注释
如果你使用Java语言编程,你必须使用Javadoc的文档格式进行注释,以便以后用javadoc生成相应的文档。
必须使用文档注释的地方有:文件头注释、类定义注释、方法注释、方法或者类内部重要的变量。
6.9 文件头注释
使用Java编程的时候,在每个源程序文件的头部进行如下的注释:
/**
* @author Tom
* @version 1.0 2002/10/28
*
* Copyright (C) 2000, 2002, KOAL, Inc.
*
*/
注意文件头注释为javadoc的文档注释类型,下面的方法、类和结构的注释也是使用javadoc的文档注释类型。
如果注释的内容超过一行,缩进也是四个空格。
在整个文件头注释结束后至少留两个空行。
注意版权一行,前一个时间是文件产生的年份,后一个是最后修改的年份。
上面的示例列出的是最少的注释内容,如果有别的内容,只要有必要,就可以添加在注释中,但一定要保证注释的排版清楚,不会造成阅读上的不便。下面的方法注释、类注释也可以是同样处理。
6.10 方法注释
使用Java编程的时候,每一个方法开头要有如下的注释:
/**
* <func-name>:<对方法的简单描述>
*
* @param <方法参数> <对方法参数的简单描述>
* @return <方法的返回值> <对返回值的简单描述>
* @throws <抛出的异常><抛出的异常的描述>
*
* @see <参见的内容>
* @deprecated <删除的内容>
*/
如果方法没有返回值,则这样书写:@return void,如果方法没有参数或者异常抛出,@param和@throws可以省略。@see和@deprecated标签只在必要的时候使用就可以了。
6.11 类注释
使用Java编程的时候,每一个类开头要有如下的注释:
/**
* <class-type> <class-name>:<对这个类的简单描述>
*
* @see
* @deprecated
*/
其中class-type说明这是个类, interface等,@see和@deprecated标签只在必要的时候使用就可以了。
6.12 方法或者类的内部注释
在方法或者类的内部,可以不使用文档注释,对于非常重要的变量或者语句,可以使用文档注释,对于一般性的说明文字,使用普通的注释就可以了。
6.13 代码修改必须增加注释
必须在修改的地方说明以下内容:
- 1. 什么时间修改
- 2. 谁修改
- 3. 修改了什么内容
- 4. 到哪里为至
- 5. 修改后的版本号(产品版本或项目代码)
增加代码的注释方法:
…..
//V1.3.1 2006-6-21 zhangsan 增加代码的原因 +{{
增加的代码
//}}
删除代码的注释方法:
…..
/*V1.3.1 2006-6-21 zhangsan 删除代码的原因 -{{
被删除的代码
}}*/
修改代码的注释方法:
…..
/*V1.3.1 2006-6-21 zhangsan 修改代码的原因 c{{
被删除的代码
*/
新改动的代码
//}}
7 表达式
7.1 如果表达式中的运算符较多,使用括号确定运算顺序
由于一种语言的运算符的优先级关系很复杂,很难一一记清楚,所以如果表达式较长,则不要使用默认的运算符顺序而使用括号来确定运算顺序。
示例:
if ((a | b) && (a & c))
word = (high << 8) | low
7.2 避免大表达式中使用赋值语句
以下两种写法都不是良好的编程风格:
area = (width = width * SCALE_FACTOR) * height;
while ( (c = getChar()) != ‘a’)
{
……
}
7.3 避免数学表达式和程序表达式混淆
if (a < b < c)中的a < b < c是个数学表达式,它并不代表 (a < b) && (b < c)的意思,而是指(a < b) < c的意思,在程序编写的时候避免使用这种a < b < c的写法。
7.4 在条件表达式中常量建议书写在前面
示例:
if (0 == a)
{
….//program
}
8 常用语句
8.1 if语句
if语句的标准写法如下:
if (expr1)
{
....
}
else
{
....
}
或者:
if (expr1)
{
....
}
else if (expr2)
{
....
}
else
{
....
}
或者:
if (expr1)
{
....
}
else if (expr2)
{
....
}
对于判断语句,遵循以下的写法(假设变量名为flag):
- 1. 如果flag是布尔型变量,则如此书写:
if (flag)
if (!flag)
- 2. 如果flag是浮点型,避免使用等于或者不等于判断: 如这样的写法不好:
if (0 == flag)
而应该使用类似这种大于等于或者小于等于进行判断:
if (flag >= -0.000001 && flag <= 0.000001)
- 3. 如果flag是整数,避免下面的写法:
if (flag)
或
if (!flag)
而应该写成
if (0 == flag)
或
if (0 != flag)
8.2 循环语句
for语句的标准写法是:
for (i = 0; i < n; i++)
{
expr2;
}
while语句的标准写法是:
while (expr)
{
....
}
do-while语句的标准写法是:
do
{
....
} while (expr);
为了保持结构紧凑,for后面的()内的内容可以省略空格。 循环语句的判断,遵循6.1的有关规则。 循环语句的内部禁止修改循环变量。
8.3 switch语句
switch语句的标准写法如下:
switch (expr)
{
case const-expr1:
....
break;
case const-expr2:
....
break;
default:
....
break;
}
switch语句的每个分支都要加break,否则一定是用注释说明。switch语句的最后一定要使用default语句,即使只有default : break。这样防止别人以为你忘记了default处理。
9 方法
9.1 避免方法参数过多
一个方法的参数建议不要超过5个。
9.2 建议方法只有唯一的出口
9.3 如果返回不是void,必须提供返回值
示例:
Integer function(Integer parameter)
{
if (null != parameter)
{
return parameter;
}
} //else的时候返回什么?
9.4 重复使用的代码用方法替代
10 类
10.1 提高类内的聚合度
高内聚指的是在进行类设计的时候强调专注于某一件事或者一个目标,并且把它做好。
如果数据成员超过10个,则这个类很有可能内聚性较差。
10.2 降低类之间的耦合度
低耦合是减少类之间的依赖程度。
10.3 努力使类的接口少而完备
一个完备的接口指使用者可以通过它(对类)作任何合理的事情。接口少,指的是类里面的方法尽可能的少。
&esmp;一个类的成员方法不应该超过20个。
11 其它
11.1 无论什么时候,为你的正式程序编写单元测试代码
即使你的方法非常简单,只有三五行,而且实现的功能非常简单,都尽可能为你的代码编写单元测试代码,对于功能复杂的核心代码,尽可能进行100%的单元测试。
11.2 建立项目内部编码规范
本文是用于公司的JAVA编程规范,对编程的一些细节并没有规定到。比如在水滴项目组和数据平台组两个项目组内部使用的变量命名规范,文件名和目录命名原则就会有很大不同,需要项目组把自己内部的编程规范文档化。另外,本规范是以Java语言作为基础制定的,如果项目组使用到了其他的语言入Python,Php,Go也应该有相应的规范,并且把它们文档化。SEPG组会整理这些规范,作为公司的技术积累的财富。