Java编码规范
前 言....................................................................... 3
1 范围..................................................................... 4
2 术语和定义............................................................... 4
2.1 原则............................................................. 4
2.2 规则............................................................. 4
2.3 建议............................................................. 4
2.4 说明............................................................. 4
2.5 正例............................................................. 4
2.6 反例............................................................. 4
3 代码布局................................................................. 4
3.1 基本格式......................................................... 4
3.2 对齐............................................................. 6
3.3 空行空格......................................................... 7
3.4 断行............................................................. 8
4 注释.................................................................... 10
5 命名规则................................................................ 14
6 声明.................................................................... 19
7 表达式与语句............................................................ 20
8 类和接口................................................................ 24
9 附编程实例.............................................................. 26
前 言
编码规范包括总则和细则两部分。总则部分是对编码的总体性规范要求,适用于多种编码语言;细则部分是在总则的规范要求下,针对具体语言的特点而提出的规范要求。本规范是编码规范的细则部分,适用于JAVA编程语言。
编写本规范的目的是为了进一步规范JAVA软件编程风格,提高软件源程序的可读性、可靠性和可重用性,确保在开发成员或开发团队之间的工作可以顺利交接,不必花很大的力气便能理解已编写的代码,以便继续维护和改进以前的工作,提高软件源程序的质量和可维护性,减少软件维护成本。
本规范的内容包括:代码布局、注释、命名规则、声名、表达式与语句、类与接口等。规范最后给出了一个编程实例供软件人员参考。
本规范分成规则性和建议性两种:对于规则性规范,要求所有软件开发人员严格执行;对于建议性规范,各项目编程人员可以根据实际情况选择执行。
自本规范实施之日起,以后新编写的和修改的代码均应执行本规范
1 范围
本标准规定了Java语言的编程规范,主要包括基本原则、布局、注释、命名规则、声明、表达式与语句、类和接口等。
本规范自生效之日起,对以后新编写的和修改的代码有约束力。
2 术语和定义
下列术语和定义适用于本标准。
2.1 原则
编程时应该坚持的指导思想。
2.2 规则
编程时必须遵守的约定。
2.3 建议
编程时必须加以考虑的约定。
2.4 说明
对此规则或建议的必要的解释。
2.5 正例
对此规则或建议给出的正确例子。
2.6 反例
对此规则或建议给出的反面例子。
3 代码布局
代码布局的目的是显示出程序良好的逻辑结构,提高程序的准确性、连续性、可读性、可维护性。更重要的是,统一的代码布局和编程风格,有助于提高整个项目的开发质量,提高开发效率,降低开发成本。同时,对于普通程序员来说,养成良好的编程习惯有助于提高自己的编程水平,提高编程效率。因此,统一的、良好的程序布局和编程风格不仅仅是个人主观美学上的或是形式上的问题,而且涉及到产品质量,涉及到个人编程能力的提高,必须要引起重视。
3.1 基本格式
【规则3-1-1】源代码文件(.java)的布局顺序是:包、import语句、类。 |
正例:
package com.zte;
importjava.awt.peer.CanvasPeer;
import java.io.*;
import com.zte.ums.uep.*;
public class ClassName
{
}
【规则3-1-2】遵循统一的布局顺序来书写import语句,不同类别的import语句之间用空行分隔。 |
说明:package语句其后可跟import语句,而且与package间隔一个空行。import包的排列顺序为java开头的包在最前面,接下来是引自外部的包,再接下来是应用程序自身的包,即import 中标准的包名要在本地的包名之前,而且按照字母顺序排列。
正例:
package com.zte;
import java.awt.peer.CanvasPeer; //java自身的包
importjava.io.*;
import com.klg.field.*; //第三方的包
import com.zte.ums.uep.*; //程序自身的包
【规则3-1-3】if、else、else if、for、while、do等语句独占一行,执行语句不得紧跟其后。不论执行语句有多少都要加 { }。 |
说明:这样可以防止书写失误,也易于阅读。
正例:
if (varible1< varible2) {
varible1 = varible2;
}
反例:
下面的代码执行语句紧跟if的条件之后,而且没有加{},违反规则。
if (varible1 <varible2) varible1 = varible2;
〖建议3-1-1〗源程序中关系较为紧密的代码应尽可能相邻。 |
说明:这样便于程序阅读和查找。
正例:
length =10;
width =5; // 矩形的长与宽关系较密切,放在一起。
strCaption = “Test”;
反例:
length =10;
strCaption = “Test”;
width =5;
3.2 对齐
【规则3-2-1】一般禁止使用制表符,必须使用空格进行缩排。缩进为4个空格。 |
说明:对于利用JBuilder等编程工具的,可以设置TAB键为4个空格代替。消除不同编辑器对制表符处理的差异。
【规则3-2-2】程序的分界符‘{’和‘}’应独占一行,‘}’同时与引用它们的语句左对齐。{ }之内的代码块使用缩进规则对齐。 |
说明:这样使代码便于阅读,并且方便注释。
do… while语句可以例外,while条件可与 } 在同一行。
正例:
void function(int var){
while (condition){
doSomething(); //与{ }缩进4格
} //与引用它们的模块左对齐
}
反例:
void function(int var){
while (condition){
doSomething();
}
}
【规则3-2-3】多维的数组如果在定义时初始化,按照数组的矩阵结构分行书写。 |
正例:
int[][] number =
{
{1, 1, 1},
{2, 4, 8},
{3, 9, 27},
{4, 16, 64}
};
【建议3-2-1】相关的赋值语句等号对齐。 |
正例:
width = 50;
length = 20;
height = 40;
3.3 空行空格
【规则3-3-1】不同逻辑程序块之间要使用空行分隔。 |
说明:空行起着分隔程序段落的作用。适当的空行可以使程序的布局更加清晰。
正例:
void doSomething()
{
Connection con =null; //数据库连接
boolean returnParameter = false; //返回
//空一行
//if代码的注释
if (reconsign == null){
returnfalse;
}
}
反例:
voiddoSomething()
{
Connection con =null; //数据库连接
boolean returnParameter = false; //返回
//if代码的注释
if (reconsign == null)
returnfalse;
}
【规则3-3-2】一元操作符如“++”、“--”、“!”、“~”、(类型)等前后不加空格。“[]”“.”这类操作符前后不加空格。 |
正例:
!value
~value
++count++
number[i]= 5;
box.getWidth();
【规则3-3-3】多元运算符和它们的操作数之间至少需要一个空格。 |
说明:空格的多少根据上下文调整。
正例:
value = oldValue;
total + value;
number+= 2;
【规则3-3-4】方法名之后不要留空格。 |
说明:方法名后紧跟左括号‘(’。
【规则3-3-5】‘(’向后紧跟,‘)’、‘,’ 、‘;’向前紧跟,紧跟处不留空格。‘,’之后要留空格。‘;’不是行结束符号时其后要留空格。 |
正例:
例子中的 凵 代表空格。
for(i凵=凵0;凵i凵<凵MAX_BSC_NUM;凵i++){
doSomething(width,凵height);
}
3.4 断行
【规则3-4-1】长表达式(超过120列)要在低优先级操作符处拆分成新行,操作符放在新行之首(以便突出操作符)。拆分出的新行要进行适当的缩进,使排版整齐。 |
说明:
断行方法:
1. 在逗号后断行
2. 在操作符前断行
3. 在低优先级操作符处断行
对齐方法:
1. 将新行与同一级别的先前行的表达式的起始端对齐。
2. 条件表达式的续行在第一个条件处对齐。
3. for循环语句的续行在初始化条件语句处对齐。
4. 函数调用和函数声明的续行在第一个参数处对齐。
5. 赋值语句的续行应在赋值号处对齐。
6. 如果上述规则导致代码排列混乱或代码左边界少于两个缩进,可用两倍缩进替代。
下面是一些断行方法调用的示例:
正例:
someMethod(longExpression1, longExpression2,longExpression3,
longExpression4, longExpression5);
var =someMethod1(longExpression1,
someMethod2(longExpression2,
longExpression3));
下面是两个断行算术表达式例子,第一个是优选方法,因为断行出现在括号表达式之外,属于较高级别的断行。
正例:
longName1= longName2 * (longName3 + longName4 - longName5)
+ 4 * longname6; //允许的断行方法
反例:
longName1= longName2 * (longName3 + longName4
-longName5) + 4 * longname6; //应该避免的断行方法
下面是两个缩排方法的例子,第一个是传统的方式,第二个例子中如果采用传统方式缩排将导致第二行和第三行右边出现太多空白,因此,采用8个空格符替代。
//传统的缩排方法,第二行与第一行的括号对齐。
正例:
someMethod(int anArg, Object anotherArg,String yetAnotherArg,
Object andStillAnother) {
...//你代码的位置
}
//由8个空格符来替代与括号对齐的方法,以避免第二行、第三行出现太多的空格符
正例:
private static synchronized horkingLongMethodName(int anArg,
Object anotherArg, StringyetAnotherArg,
ObjectandStillAnother)
{
...//你代码的位置
}
对于if语句的行封装通常使用8空格规则,因为传统的4空格缩排方式使得有些语句容易被忽略掉,使if语句体难以理解。例如:
反例:
//不允许使用下面的缩进方法
if ((condition1 && condition2)
|| (condition3 &&condition4)
||!(condition5 &&condition6))
{ //不好的缩进
doSomethingAboutIt(); //这样对齐的缩进方式很容易让阅读的人忽略掉这一行
}
正例:
//宜采用下面的缩进方法(分成三行的情况)
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;
【规则3-4-2】方法声明时,修饰符、类型与名称不允许分行书写。 |
正例:
public static doublecalculateArea(double width, double height);
反例:
public static double
calculateArea(doublewidth, double height);
4 注释
注释有助于理解代码,有效的注释是指在代码的功能、意图层次上进行注释,提供有用、额外的信息,而不是代码表面意义的简单重复。
Java注释的方式有:
行注释:“// 注释内容”和“/**注释内容 */”两种注释形式。
文档型注释:“/** 注释内容 */”分成多行书写的形式,注释内容里包含标签。
一般类公共变量的声明采用行注释。
类、接口、构造函数、方法等的声明采用文档型注释
【规则4-1】注释符与注释内容之间要用一个空格进行分隔。 |
正例:
/* 注释内容 */
// 注释内容
反例:
/*注释内容*/
//注释内容
【规则4-2】注释使用中文注释。与doc有关的标准英文单词标签保留。 |
说明:文档型注释描述了Java类(Java classes),接口(interfaces),构造函数(constructors)、方法(methods)和域(fields)。每一个文档注释都包含在/**…*/分隔符中,每一个类(class)、接口(interface)或成员(member)都有一个注释。这些注释应该只出现在声明(declaration)前。
标签 | 用处 | 用途 |
@author 作者的名称 | 类、接口 | 说明特定某一段程序代码的作者。每一个作者各有一个标记。 |
@Deprecated | 类、方法 | 说明该类的应用程序编程接口 (API) 已被废弃,因此应不再使用。 |
@exception name description | 方法 | 说明由方法发出的异常。一个异常采用一个标记,并要给出异常的完整类名。 |
@param name 参数名的描述 | 方法 | 用来说明传递给一个方法的参数,其中包括参数的类型/类和用法。每个参数各有一个标记。 |
@return 方法返回值的描述 | 方法 | 若方法有返回值,对该返回值进行说明。应说明返回值的类型/类和可能的用途。 |
@since | 类、方法 | 例如: since JDK 1.1:说明自从有 JDK 1.1 以来,该项已存在了多长时间。 |
@see 类名 | 类、接口、方法、字段 | 在文档中生成指向特定类的超文本链接。可以并且应该采用完全合法的类名。 |
@see ClassName#member functionName | 类、接口、方法、字段 | 在文档中生成指向特定方法的超文本链接。可以并且应该采用完全合法的类名。 |
@version 版本号 | 类、接口 | 说明特定一段代码的版本信息。 |
【规则4-3】类、接口头部必须进行注释。 |
说明:注释必须列出:类、接口编号、名称、内容摘要等。
类编号由功能模块编号和类名两部分组成,中间用“_”隔开,功能模块编号使用该类所在
的功能模块的编号,类名用类的名称。例如:M01_Employee。
正例:
下面是类头部的中文注释:
/**
* 类编号:
* 类名称:
* 内容摘要://说明主要功能。
* @author
*/
【规则4-4】公共方法前面应进行文档型注释。 |
说明:注释必须列出:方法编号、主要功能、参数类型、输入参数、返回值、调用的前置条件和后置条件、异常说明、关键算法、可见性决策等。
正例:
下面是公共方法头部的注释:
/**
* 方法名称:
*内容摘要: <列出主要功能、调用说明、异常说明、业务逻辑等>
* @param
* @return
* @throws
*/
publicString getName(String name)
{
return name;
}
【规则4-5】注释应与其描述的代码相近,对代码的注释应放在其上方(需与其上面的代码用空行隔开)或右方(对单条语句的注释)相邻位置,不可放在下面。 |
说明:在使用缩写时或之前,应对缩写进行必要的说明。避免在代码行的末尾添加注释;行尾注释使代码更难阅读。不过在批注变量声明时,行尾注释是合适的;在这种情况下,将所有行尾注释在公共制表位处对齐。
正例:
如下书写结构比较清晰
// 获得子系统索引
subSysIndex= data.getSysIndex;
// 代码段1注释
[ 代码段1 ]
/* 代码段2注释 */
[ 代码段2 ]
反例1:
如下例子注释与描述的代码相隔太远。
/* 获得子系统索引 */
subSysIndex= subSys.getSysIndex();
反例2:
如下例子注释不应放在所描述的代码下面。
subSysIndex = subSys.getSysIndex();
/* 获得子系统索引 */
反例3:
如下例子,显得代码与注释过于紧凑。
/* 代码段1注释*/
[ 代码段1 ]
/* 代码段2注释 */
[ 代码段2 ]
【规则4-6】注释与所描述内容进行同样的缩进。 |
说明:这样可使程序排版整齐,并方便注释的阅读与理解。
正例:
如下注释结构比较清晰
int doSomething(){
/* 代码段1注释 */
[ 代码段1 ]
/* 代码段2注释 */
[ 代码段2 ]
}
反例:
如下例子,排版不整齐,阅读不方便;
int doSomething()
{
/*代码段1注释 */
[ 代码段1]
/*代码段2注释 */
[ 代码段2]
}
〖规则4-7〗包含在{ }中代码块的结束处要加注释,便于阅读。特别是多分支、多重嵌套的条件语句或循环语句。 |
说明:此时注释可以用英文,方便查找对应的语句。
正例:
void doSomething(){
if (…) {
…
while (…) {
…
} // end of while (…) // 指明该条while语句结束
…
} // end of if (…) // 指明是哪条语句结束
} // endof void main() // 指明函数的结束
〖规则4-8〗对分支语句(条件分支、循环语句等)必须编写注释。 |
说明:这些语句往往是程序实现某一特殊功能的关键,对于维护人员来说,良好的注释有助于更好的理解程序,有时甚至优于看设计文档。
〖建议4-1〗Java语言中,公共的属性采用单行文档注释,对于需要比较多的声明的,可进行多行注释。 |
说明:如果是Javadoc注释,属性可以采用文档型注释。
正例:
对于public型变量的单行声明:
/**classVar1 对classVar1的声明 */
publicstatic int classVar1;
对于public型变量的多行声明:
/**
* classVar1 对classVar1的声明第一行
* 对classVar1的声明第二行(继续对classVar1的声明)
*/
publicstatic int classVar1;
对于public型变量的多行声明:
/**
* classVar1 对classVar1的声明第一行
* 对classVar1的声明第二行(继续对classVar1的声明)
*/
publicstatic int classVar1;
〖建议4-2〗通过对方法、变量等正确的命名以及合理地组织代码结构,使代码成为自注释的。 |
说明:清晰准确的方法、变量的命名,可增加代码的可读性。
〖建议4-3〗尽量避免在注释中使用缩写,特别是不常用缩写。 |
说明:在使用缩写时,应对缩写进行必要的说明。
5 命名规则
首字母小写后续每个单词首字母大写。
接口:I*****Dao
接口实现类:*****DaoImpl
好的命名规则能极大地增加可读性和可维护性。同时,对于一个有上百个人共同完成的大项目来说,统一命名约定也是一项必不可少的内容。本章对程序中的所有标识符(包括包、变量名、控件名、常量名、方法名、类名、接口等)的命名做出约定。
三种命名规范说明:
Pascal规范:第1个字符大写,目标名中的每个单词的第1个字母也大写,比如InvoiceNumber或者PrintInvoice。其他的所有字符都小写。
Camel规范:第1个字符不大写,但目标名中的每个单词的第1个字母大写,比如,invoiceNumber。其他的所有字符都小写。
匈牙利规范:在目标名中加入表示类型的前缀,如strName。
【规则5-1】标识符要采用英文单词或其组合,便于记忆和阅读,切忌使用汉语拼音来命名。 |
说明:标识符应当直观且可以拼读,可望文知义,避免使人产生误解。程序中的英文单词一般不要太复杂,用词应当准确。
【规则5-2】标识符只能由26个英文字母,10个数字及下划线的一个子集来组成,并严格禁止使用连续的下划线。用户定义的标识符下划线不能出现在标识符的头尾,数字也不能出现在标识符的头部。 |
说明:这样做的目的是为了使程序易读。因为 variable_name 和 variable__name 很难区分,下划线符号‘_’若出现在标识符头或结尾,容易与不带下划线‘_’的标识符混淆。
【规则5-3】标识符应当使用完整的英文描述,标识符的命名应当符合“min-length && max-information”原则,谨慎使用缩写。 |
说明:对于标识符应当使用完整的英文进行描述,对于整个描述较长的,可对单词进行缩略。较短的单词可通过去掉“元音”形成缩写,较长的单词可取单词的头几个字母形成缩写,一些单词有大家公认的缩写,常用单词的缩写必须统一。协议中的单词的缩写与协议保持一致。对于某个系统使用的专用缩写应该在某处做统一说明。设计命名中应该慎用缩写命名。如要采用,则应采用统一的缩略规则,并且在代码的相应部分统一采用缩写。例如,采用num作为number的缩写,那么在整个代码中应该始终使用该缩写。在使用缩写时,在使用缩写时,应该按着专业术语的要求大小写,例如,System.IO,而不是 System.Io。
正例:如下单词的缩写能够被大家认可:
temp 可缩写为 tmp ;
flag 可缩写为 flg ;
statistic 可缩写为 stat ;
increment 可缩写为 inc ;
message 可缩写为 msg ;
以下是一些常用缩写:
常用词 | 缩写 |
argument | arg |
buffer | buf |
clear | clr |
clock | clk |
compare | cmp |
configuration | cfg |
context | ctx |
delay | dly |
device | dev |
disable | dis |
display | disp |
enable | en |
error | err |
function | fnct |
hexadecimal | hex |
initialize | init |
mailbox | mbox |
manager | mgr |
maximum | max |
message | msg |
minimum | min |
multiplex | mux |
operating system | OS |
parameter | param |
previous | prev |
priority | prio |
read | rd |
ready | rdy |
register | reg |
schedule | sched |
semaphore | sem |
stack | stk |
synchronize | sync |
timer | tmr |
trigger | trig |
write | wr |
【规则5-4】遵循统一的规范来书写包的声明,必须以com.zte开头。 |
说明:对于包的声明,要遵循统一的命名规范来对包的声明进行说明。
大多数Java源文件的第一个非注释行是一个package语句。
包名总是小写,并且前缀是一个顶级域名(如当前的com,edu,gov,mil,net,org)或服从ISO Atandsrd 3166,1981中规定的两英文字母国家标识符。
包名称的随后部分根据组织自身的命名规范变化。这样的规范可通过指定分公司、项目等来确定。
正例:
package com.zte;
【规则5-5】类名采用大小写结合的方法,构成类名的每个单词的首字母的首字母也必须大写,即采用Pascal规范。在构成类名的单词之间不用下划线。 |
【规则5-6】接口命名和类命名规范相同。 |
【规则5-7】采用应用领域相关的术语来命名。 |
说明:软件开发人员应注意软件用户的一些约定术语,不应当随意的创造术语,这会降低软件的易用性。
【规则5-8】程序中不要出现仅靠大小写区分的相似的标识符。 |
说明:命名时应避免采用几乎相同的名称。例如,变量名称persistentObject和persistentObjects不应当同时运用;anSqlDatabase和anSQLDatabase也不应同时使用。
【规则5-9】用正确的反义词组命名具有互斥意义的变量或相反动作的函数等。 |
说明:下面是一些在软件中常用的反义词组。
add / remove ; begin / end ; create / destroy ; insert / delete ;
first / last ; get / set ; increment / decrement ; put / get ;
add / delete ; lock / unlock ;open / close ; min / max ;
old / new ; start / stop ;next / previous ;source / target ;
show / hide ; send / receive ;source /destination ;cut / paste ;
up / down
【规则5-10】常量名都要使用大写字母, 用下划线 ‘_’ 分割单词。 |
正例:static final intMIN_WIDTH = 4;
staticfinal int MAX_WIDTH = 999;
staticfinal int GET_THE_CPU = 1;
【规则5-11】一般变量名不得取单个字符(如i、j、k等)作为变量名,局部循环变量除外。 |
说明:变量,尤其是局部变量,如果用单个字符表示,很容易出错(如l误写成1),而编译时又检查不出,则有可能增加排错时间。变量的命名应当选择精炼、意义明确的名字,才能简化程序语句,改善对程序功能的理解。
【规则5-12】类变量、属性、方法参数、方法局部变量都要采用Camel规范命名,并要用完整的英文描述符命名。 |
说明: 1. 要避免方法局部变量和类属性名相同,以免产生混淆。
2. 方法参数命名,如果可能的话,使用和要赋值的类成员数据一样的名字。
【规则5-13】控件命名应采用完整的英文描述符命名,名字的前缀是控件类型名,即采用匈牙利规范。 |
说明:这样容易区分一个控件的目的和它的类型,容易在一个表里找到各个控件。
正例: btnOk
listCustomer
newFiles
【规则5-14】方法名应当能体现方法的作用,必须用小写字母开头的单词组合而成,即采用Camel规范,且应当使用“动词”或者“动词+名词”(动宾词组)。 |
说明:方法名力求清晰、明了,通过方法名就能够判断方法的主要功能。多个单词组合而成的方法名中,第一个单词后面的单词采用大小写字母结合的形式(首字母大写),但专有名词不受限制。单词间不用下划线连接。
【规则5-15】获取性方法的命名有两类,一种是判断性的操作(获取属性的状态,返回值为boolean),如判断某些控件的状态等,对于这些操作,应当是以is为方法声明的开头。另外一种是获取返回值的操作,对一这种操作,应当以get开头。 |
正例: getFirstName()
getAccountNumber()
isPersistent()
isAtEnd()
【规则5-16】属性设置性的方法命名以set开头,后紧跟属性名。 |
说明:根据这个标准来命名一个类的方法,可以很容易的让人明白这个方法的基本功能。
正例: setFirstName(String firstName)
setAccountNumber(int accountNumber)
setReasonableGoals(VectornewGoals)
setPersistent(booleanisPersistent)
setAtEnd(boolean isAtEnd)
【规则5-17】To型方法:表示类型转换的方法一般用to开头。 |
说明:这些方法主要用来进行类型转换。
正例: toString()
【规则5-18】编译单元(源码文件)的名称应与文件内定义的主要的类或接口的名字相同,大小写也应相同。扩展名为 .java 。 |
〖建议5-1〗避免直接使用数字常量,提高代码可读性。 |
说明:指定常量(final,static变量)可以使得代码更容易被理解与维护。
正例:
class USNFixed
{
privatestatic final int ARRAY_SIZE = 1000;
int[]getArray ()
{
return new int [ARRAY_SIZE]; //正确
}
}
〖建议5-2〗类提供toString()方法,以方便调试。 |
〖建议5-3〗尽量避免名字中出现数字编号,如value1、value2等,除非逻辑上的确需要编号。 |
〖建议5-4〗标识符前最好不加项目、产品、部门的标识。 |
说明:这样做的目的是为了代码的可重用性。
〖建议5-5〗对于界面控件名称比较长的,可用“控件缩写+控件功能描述”的命名方式。 |
正例: btnOpenNewFile
6 声明
【规则6-1】一行只声明一个变量。 |
正例:
int level;
int size;
全局变量 静态化常量 全部大写。
反例:
int level, size;
【规则6-2】一个变量有且只有一个功能,不能把一个变量用于多种用途。 |
反例:
void myMethod() {
boolean myFlag = false;
myFlag = isVisible(myView) //作为可见性判断标志
//使用myFlag做其它操作
……
myFlag = isEnable(myComponent) //作为可用性判断标志
}
〖建议6-1〗变量声明应该只放在代码段的开始部分。最好不要到使用时才声明变量。对象类变量在函数体结束后,手工设置为null值,以利于资源的回收。 |
正例:
void myMethod()
{
int myInt = 0; //方法块的开始
//其它语句
}
7 表达式与语句
表达式是语句的一部分,它们是不可分割的。表达式和语句虽然看起来比较简单,但使用时隐患比较多。本章归纳了正确使用表达式和if、for、while、switch等基本语句的一些规则与建议。
【规则7-1】每一行应该只包括一个语句。 |
说明:复杂的语句阅读起来难于理解,并容易隐含错误。
正例:
argv++;
反例:
argv++; argc--;
if(s4 == null) s4 = new String(“Joy”);
【规则7-2】在表达式中使用括号,使表达式的运算顺序更清晰。 |
说明:由于将运算符的优先级与结合律熟记是比较困难的,为了防止产生歧义并提高可读性,即使不加括号时运算顺序不会改变,也应当用括号确定表达式的操作顺序。
正例:
if (((iYear % 4 == 0)&&(iYear % 100 != 0)) || (iYear % 400 == 0))
反例:
if (iYear % 4 == 0 &&iYear % 100 != 0 || iYear % 400 == 0)
【规则7-3】当复合语句作为控制流程的一部分时,应该用‘{ }’把所有的复合语句括起来,即使只有一句简单语句。 |
说明:这样可以更方便地加入语句而不会由于忘掉加括号而引起的偶然性的错误。
正例:
intcount;
...
myMethod(){
if (condition) {
count = 1;
}
}
【规则7-4】不可将浮点变量用“==”或“!=”与任何数字比较。 |
说明:无论是float还是double类型的变量,都有精度限制。所以一定要避免将浮点变量用“==”或“!=”与数字比较,应该转化成“>=”或“<=”形式。
正例:
if ((fResult >= -EPSINON)&& (fResult <= EPSINON))
反例:
if (fResult == 0.0) //隐含错误的比较
其中EPSINON是允许的误差(即精度)。
【规则7-5】在switch语句中,每一个case分支必须使用break结尾,最后一个分支必须是default分支。 |
说明:避免漏掉break语句造成程序错误。有时编程逻辑需要,可以几个case语句共用一个语句块,对这种情况必须加注释进行说明。
正例:
switch (iMessage)
{
caseSPAN_ON:
[处理语句]
break;
case SPAN_OFF:
[处理语句]
break;
default:
[处理语句]
break;
}
〖建议7-1〗避免在“if”条件中赋值。 |
说明:Java编译器对boolean型变量在if条件语句中的赋值时合法的,对整型变量的赋值是不合法的。
〖建议7-2〗带值的返回语句不需要用括号‘()’。 |
说明:除非有时不得不用括号使返回结构更加明显。
正例:
return;
returnmyDisk.size();
return(size ? size : defaultSize); //用括号使返回结构更加明显。
〖建议7-3〗循环嵌套次数不大于3次。 |
〖建议7-4〗do while语句和while语句仅使用一个条件。 |
说明:保持程序简洁。如果需要判断的条件较多,建议用临时布尔变量先计算是否满足条件。
正例:
boolean bCondition;
do
{
……..
bCondition =((tAp[iPortNo].bStateAcpActivity != PASSIVE)
||(tAp[iPortNo].bStateLacpActivity != PASSIVE))
&& (abLacpEnabled[iPortNo])
&& (abPortEenabled[iPortNo])
} while (bCondition);
〖建议7-5〗在多重循环中,如果有可能,应当将最长的循环放在最内层,最短的循环放在最外层,以减少CPU跨切循环层的次数。 |
正例:
for (iCol = 0; iCol< 5; iCol++)
{
for (iRow = 0; iRow< 100; iRow++)
{
iSum = iSum + aiDate[iRow][iCol];
}
}
反例:
for (iRow = 0; iRow< 100; iRow++)
{
for (iCol = 0; iCol< 5; iCol++)
{
iSum = iSum + aiDate[iRow][iCol];
}
}
〖建议7-6〗不可在for 循环体内修改循环变量,防止for 循环失去控制。 |
8 类和接口
【规则8-1】类内部的代码布局顺序:类变量、属性、构造函数、方法。 |
正例:
class Test
{
privateint exampleVar;
public string name;
publicTest()
{
…;
}
public voidsetName(string name)
{
…;
}
private void method()
{
…
}
}
〖建议8-1〗功能相关的方法放在一起。 |
说明:如接口中关系较紧密的的几个方法,类属性的get和set 方法,有调用关系的方法,重载的方法等有相近或相关的方法尽可能放在一起,方便阅读。
正例:
classSample extends Object
{
int ivar1;
int ivar2;
String name;
Sample(inti, int j)
{
ivar1 = i;
ivar2 = j;
}
publicvoid setName(String name)
{
this.name = name;
}
publicString getName()
{
return this.name;
}
intmethod1 ()
{
…
method2();
}
voidmethod2()
{
…
}
}
〖建议8-2〗函数的参数个数不宜超过4个。 |
说明:过多的函数参数会导致性能降低。
〖建议8-3〗使程序结构体现程序的目的。 |
正例:
returnbooleanExpression;
反例:
if(booleanExpression)
{
return true;
}
else
{
return false;
}
〖建议8-4〗保证内部类定义成private,提高类的封装性。 |
〖建议8-5〗嵌套内部类不能超过两层。 |
〖建议8-6〗一个接口可以有多个实现类,实现类共同的变量在接口里声明。 |
9 附编程实例
/**
* 版权所有:版权所有(C) 2004,中兴通讯
* 文件编号:M01_Reconsign.mdl
* 文件名称: ReconsignOpr.Java
*系统编号:Z0001002
*系统名称:售后服务管理(系统用户)
*模块编号:04
*模块名称:合同模块
*设计文件:Reconsign.mdl
* 完成日期:2004-7-01
*作 者:小王
*内容摘要: 该代码文件的主要功能是办事处补发货网上流程管理,办事处创建补发货申请,然后提交事业部计划
* 部批准。计划部再根据库存情况,同意或拒绝此补发货申请。可以在系统中查询当前补发货单状态。
*
* 主件中包含一个控制类ReconsignOpr,所有功能都是通过该类实现,类中的代码包括个区段:类变量
* 区、类属性区、构造函数区、类方法区。
*
* 文件调用:调用该类时要实例化该类。在Action类中调用
*/
package com.zte.ecc.epm.reconsign.apply;
import java.sql.Connection;
import java.util.ArrayList;
import java.util.List;
import com.zte.ecc.authority.TitleConstantsData;//补发货查询接口
import com.zte.ecc.epm.reconsign.apply.dao.AppendApplyDAO;//插入数据
import com.zte.ecc.epm.reconsign.apply.dao.ChangeApplyDAO;//变更申请补发货申请的DAO
import com.zte.ecc.epm.reconsign.apply.dao.OtherApplyDAO;//其他申请的DAO
import com.zte.ecc.epm.reconsign.apply.dao.ReconsignDAO;//补发货申请的DAO
import com.zte.ecc.epm.reconsign.apply.model.AppendApplyModel;//插入数据的模型
import com.zte.ecc.epm.reconsign.apply.model.ChangeApplyModel;//变更申请补发货申请的模型
import com.zte.ecc.epm.reconsign.apply.model.OtherApplyModel;//其他申请的模型
import com.zte.ecc.epm.reconsign.apply.model.ReconsignModel;//补发货申请的模型
import com.zte.ecc.epm.reconsign.util.ReconsignUtil;//补发货申请界面
import com.zte.ecc.epm.util.common.EPMGlobe;//EPM
import com.zte.ecc.epm.util.number.NumberUtil;//NumberUtil
import com.zte.ecc.util.ACL.AccessControl; //访问权限控制
import com.zte.ecc.util.ACL.Department; //部门权限控制
import com.zte.ecc.util.ACL.DepartmentUtil; //部门界面权限控制
import com.zte.ecc.util.database.BaseDAO;
import com.zte.ecc.util.tracer.Debug; //调试
import com.zte.ecc.web.util.User;
/**
* 类 编 号:M01_ReconsignOpr
* 类 名 称: ReconsignOpr
* 内容摘要: 办事处补发货网上流程管理,办事处创建补发货申请,然后提交事业部计划部批准,计划部再根据库
* 存情况同意或拒绝此补发货申请。可以在系统中查询当前补发货单状态。
* @author 小曹
*/
public class ReconsignOpr implements ReconsignManager{
//类变量区开始
private int index= 0;//补发货申请的数据对象索引
//类变量区结束
//属性区开始
/**
* 补发货申请的数据对象
*@see com.zte.ecc.epm.reconsign.apply.model.ReconsignModel
*/
publicReconsignModel reconsign = null;
/**
* 私有的数据库连接
*@see java.sql.Connection 数据库连接
*/
privateConnection con = null;
/**
* 获取reconsign
* @return ReconsignModel 返回一个ReconsignModel对象
*/
publicReconsignModel getReconsign() {
return reconsign;
}
/**
*设置属性reconsign
* @param reconsign 被设置的属性的ReconsignModel对象
*/
public voidsetReconsign(ReconsignModel reconsign) {
this.reconsign = reconsign;
}
/**
* 获取数据库连接con
* @return Connection返回一个Connection对象
*/
publicConnection getCon() {
return con;
}
/**
* 设置属性 con
* @param con 属性con被设置的参数值
*/
public voidsetCon(Connection con) {
this.con = con;
}
//属性区结束
//构造函数区开始
/**
* @roseuid 407F4BB70119
*/
public ReconsignOpr(){
}
//构造函数区结束
//方法区开始
/**
* 方法名称:updateReconsign
* 内容摘要: 修改补发货申请的数据象,将修改后的结果保存到数据库,若成功,提交数据,并返回true;
* 否则,回滚数据,并返回false。
* @param reconsign 补发货申请的数据对象
* @param user ECC用户对象
* @return boolean 是否成功
* @throws Exception
* @roseuid 407F4BB70128
*/
public boolean updateReconsign(ReconsignModelreconsign, User user)
throws Exception {
Connectioncon = null; //数据库连接
boolean returnParameter = false; //返回
//如果补发货申请的数据对象不存在直接返回失败
if (reconsign == null)
returnfalse;
//保存补发货申请到数据库
try {
//建立数据库连接
con =BaseDAO.getConnection();
con.setAutoCommit(false);
//取得DAO对象
ReconsignDAOreconsignDAO = new ReconsignDAO(con);
//设置补发货数据对象
StringcurrentDate = EPMGlobe.getCurrentDate(); //当前时间
reconsign.setLastUpdatedBy(user.getUserId());//设置最后修改人 reconsign.setLastUpdatedDate(currentDate); //设置最后修改时间
reconsign.setState(ReconsignUtil.RECONSIGN_STATE_CREATED);//创建状态
//更新数据
reconsignDAO.update(reconsign,user);
returnParameter= true; //返回成功
con.commit();//提交数据库
con.setAutoCommit(true); //设置数据库连接的事务为自动提交
} catch (Exception ex) {
//回滚操作
try {
con.rollback();//回滚数据库操作
}catch(Exceptionex1) {
//
}
//打印错误日志
Debug.printErr(
this.getClass().getName()+ ".updateReconsign(ReconsignModel,String, User) error:"+ ex);
throw ex; //抛出Exception类型异常
} finally {
//关闭数据库连接
try {
con.setAutoCommit(true); //设置数据库连接的事务为自动提交
} catch (Exceptionex) {
//
}
BaseDAO.closeConnection(con); //关闭数据库连接
}
return returnParameter;//返回是否成功
}
/**
* 方法名称:createReconsign
* 内容摘要: 创建一个补发货申请的数据象,将创建后的结果保存到数据库,若成功,提交数据,并返回true;
* 否则回滚数据,并返回false。
* @param reconsign 补发货申请的数据对象
* @param user ECC用户对象
* @return boolean 是否成功
* @throws Exception
* @roseuid 407F4BB70139
*/
public boolean createReconsign(ReconsignModelreconsign, User user)
throws Exception {
Connection con = null;
boolean returnParameter = false; //缺省值为false
//如果补发货申请的数据对象不存在直接返回失败
if (reconsign == null)
returnreturnParameter;
//创建补发货申请到数据库
try {
//建立数据库连接
con =BaseDAO.getConnection();
con.setAutoCommit(false);
//取得DAO对象
ReconsignDAO reconsignDAO = new ReconsignDAO(con);
String currentDate =EPMGlobe.getCurrentDate();//取得当前时间
//设置补发货数据对象
reconsign.setCreatedBy(user.getUserId());//设置创建人
reconsign.setCreatedDate(currentDate); //设置创建时间为当前时间
reconsign.setLastUpdatedBy(user.getUserId());//设置最后修改人
reconsign.setLastUpdatedDate(currentDate); //设置最后修改时间
reconsign.setState(ReconsignUtil.RECONSIGN_STATE_CREATED); //创建状态
// 添加补发货申请到数据库
reconsignDAO.create(reconsign,user);
con.commit();//提交补发货数据
returnParameter= true; //返回成功
} catch (Exception ex) {
try {
con.rollback();//回滚操作
} catch (Exception ex1) {
//
}
//显示错误信息
Debug.printErr(
this.getClass().getName()
+".createReconsign(ReconsignModelreconsign, User user) error:"
+ ex);
throw ex; //抛出Exception类型异常
} finally {
try {
con.setAutoCommit(true);//设置数据库为自动提交
} catch (Exception ex) {
//
}
BaseDAO.closeConnection(con);//关闭数据库连接
}
return returnParameter;//返回是否成功
}
/**
* 方法名称:commitReconsign
* 内容摘要: 提交一个补发货申请单,提交时生成一个补发货申请编号,若存存就修改原来的补发货单,
* 若不存在则增加一个补发货单,将结果保存到数据库,若成功,提交数据,并返回true;否则, 回
* 滚数据,并返回false。
* @param reconsign 补发货申请的数据对象
* @param user ECC用户对象
* @return boolean 是否成功
* @throws Exception
* @roseuid 407F4BB70157
*/
public boolean commitReconsign(ReconsignModelreconsign, User user)
throws Exception {
Connection con = null;
boolean returnParameter = false; //缺省返回值为false
//如果补发货申请的数据对象不存在直接返回失败
if (reconsign == null)
returnfalse;
try {
//建立数据库连接
con =BaseDAO.getConnection();
con.setAutoCommit(false);
//取得DAO对象
ReconsignDAOreconsignDAO = new ReconsignDAO(con);
String currentDate =EPMGlobe.getCurrentDate();//取得当前时间
//设置补发货数据对象
reconsign.setLastUpdatedBy(user.getUserId());//设置最后修改人
reconsign.setLastUpdatedDate(currentDate); //设置最后修改时间
reconsign.setCommitedDate(currentDate); //设置提交时间
reconsign.setCommitedBy(user.getUserId());//设置提交人
reconsign.setState(ReconsignUtil.RECONSIGN_STATE_COMMITED); //设置状态
//提交时生成补发货申请编号,防止产品事业部变化时,编号不能及时同步改变,
Department dept =
(new DepartmentUtil()).getDeptByID(reconsign.getDivisionID(),con); //事业部对象
StringstrNO = NumberUtil.getNOForObject(reconsign);//获得补发货数据对象的编号
if (strNO!= null) {
strNO = strNO.substring(11);
}
//补发货申请编号格式,格式如:CDMA事业部-2004-06-21-003
strNO =dept.getDeptName() + "-" + EPMGlobe.getCurrentDate() + "-"+strNO;
reconsign.setApplyNO(strNO); //设置补发货对象的补发货申请单号
//如果补发货申请编号已存存就修改,否则新增
if (reconsign!= null&&reconsign.getOid() > 0) {
reconsignDAO.update(reconsign, user); //保存补发货对象
} else {
reconsign.setCreatedBy(user.getUserId());//设置创建人
reconsign.setCreatedDate(currentDate); //设置创建时间
reconsignDAO.create(reconsign, user); //在数据库中增加当前补发货申请
}
con.commit();//提交到数据库
returnParameter= true; //返回成功
} catch (Exception ex) {
try {
con.rollback();//数据回滚
} catch (Exception ex1) {
//
}
//显示错误信息
Debug.printErr(
this.getClass().getName()
+".commitReconsign(ReconsignModel,String, User) error:"
+ ex);
throw ex; //抛出Exception类型异常
} finally {
try {
con.setAutoCommit(true); //设置数据连接为自动提交
} catch (Exceptionex) {
//
}
BaseDAO.closeConnection(con);//关闭数据库连接
}
return returnParameter; //返回提交是否成功
}
/**
* 方法名称:setReconsignState
* 内容摘要: 设置补发货申请状态,在01 updateReconsign 保存补发货申请、02createReconsign
* 创建补发货申请、03commitReconsign 提交补发货申请将调用此方法。
* @param reconsign
* @param oid 补发货申请的OID
* @param state 补发货申请的设置的状态
* @param user ECC用户对象
* @return boolean 是否成功
* @throws Exception
* @roseuid 407F4BB70157
*/
public boolean setReconsignState(long oid,String state, User user)
throws Exception {
Connection con = null;
boolean returnParameter = false; //缺省返回值为false
//如果申请单不合法则直接返回失败
if (oid <= 0)
returnfalse;
try {
//建立数据库连接
con =BaseDAO.getConnection();
con.setAutoCommit(false);
ReconsignDAOreconsignDAO = new ReconsignDAO(con); //获得补发货单的DAO对象
reconsignDAO.setState(oid,state, user); //设置补发货单的状态
con.commit();//提交到数据库
returnParameter= true; //返回成功
} catch (Exception ex) {
try {
con.rollback();//数据回滚
} catch (Exception ex1) {
//
}
//显示错误信息
Debug.printErr(
this.getClass().getName()
+".setReconsignState(ReconsignModel,String, User) error:"
+ ex);
throw ex; //抛出Exception类型异常
} finally {
try {
con.setAutoCommit(true);//提交结果到数据库
} catch (Exception ex) {
//
}
BaseDAO.closeConnection(con);//关闭连接
}
return returnParameter; //返回是否成功
}
/**
* 方法名称:deleteReconsign
* 内容摘要: 删除补发货申请,补发货申请在未提交请前可以删除。
* @param reconsignId,补发货申请ID
* @param user ECC用户对象
* @return boolean 是否成功
* @throws Exception
* @roseuid 407F4BB70128
*/
public boolean deleteReconsign(long reconsignId,User user) throws Exception {
Connection con = null;
boolean returnParameter = false; //缺省返回值为false
//如果申请单不合法则直接返回失败
if (reconsignId <=0)
returnfalse;
try {
//建立数据库接连接
con =BaseDAO.getConnection();
con.setAutoCommit(false);
ReconsignDAO reconsignDAO = new ReconsignDAO(con); //获得补发货的DAO对象
reconsignDAO.delete(reconsignId,user); //删除数据库
returnParameter= true; //设置为提交成功
con.commit();//向数据库提交
con.setAutoCommit(true); //设置连接为自动提交
} catch (Exception ex) {
try {
con.rollback();//回滚操作
} catch (Exception ex1) {
//
}
//显示错误信息
Debug.printErr(
this.getClass().getName()
+".deleteReconsign(ReconsignModel,String, User) error:"
+ ex);
throw ex; //抛出Exception类型异常
} finally {
try {
con.setAutoCommit(true);//提交
} catch (Exception ex) {
//
}
BaseDAO.closeConnection(con);//关闭连接
}
return returnParameter; // 返回是否成功
}// enddeleteReconsign
//方法区结束
}// end class ReconsignOpr