1.亚信移动客户事业部Java编码规范V 1.0

更新时间:2024-06-07 12:19:01 阅读量: 综合文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

AsiaInfo 软件规范 移动客户事业部Java语言编码规范 软件规范 编写 审批 文档版本 编码规范编制小组 V1.9 编写时间 审批时间 2014.8 亚信科技(中国)有限公司版权所有 文档中的全部内容属亚信科技(中国)有限公司所有, 未经允许,不可全部或部分发表、复制、使用于任何目的。

文档修订摘要

日期 修订号 描述 根据各研发中心、及google等参考文档,汇总新建文档,划定制定范围、定文档目录结构;根据目录结构整理各章节规范,命名规范(宫迎宾)、布局规范(周琪宏)、注释规范(郑园园)、语句规范(彭振球)、日志规范(马万平)、异常规范(马万平)。 著者 宫迎宾、周琪宏、郑园园、彭振球、马万平 审阅者 日期 2014-8-4 1 李玉和 2014-8-5 2014-8-6 2 宫迎宾、周琪宏、周园Java组内增减,评审,定草稿版本v0.1。 园、彭振球、马万平 Java,c++,db,web组汇合评审,定草稿v0.2 周琪宏、宫迎宾增加名词解释(驼峰式、K&R, 魔术数字、CAS机制) 对文档格式排版进行统一格式调整。 对文档示例代码格式调整。 周琪宏、宫迎宾 王霄 周琪宏 李玉和 2014-8-6 2014-8-7 2014-8-7 2014-8-7 2014-8-8 3 4 5 6 肖展伟 肖展伟 肖展伟 宫迎宾 2014-8-7 2014-8-7 2014-8-7 2014-8-8 亚信科技(中国)有限公司版权所有

文档中的全部内容属亚信科技(中国)有限公司所有, 未经允许,不可全部或部分发表、复制、使用于任何目的。

目录

1. 概述 ......................................................................................................................................................... 0 1.1. 1.2. 1.3. 1.4.

编制说明 .......................................................................................................................................... 0 适用范围 .......................................................................................................................................... 0 参考文档 .......................................................................................................................................... 0 术语解释 .......................................................................................................................................... 0

2. 命名规范 ................................................................................................................................................. 2 2.1. 2.2. 2.3. 2.4. 2.5. 2.6. 2.7.

包名 .................................................................................................................................................. 2 类名 .................................................................................................................................................. 2 方法名 .............................................................................................................................................. 3 常量名 .............................................................................................................................................. 4 变量名 .............................................................................................................................................. 4 参数名 .............................................................................................................................................. 5 局部变量名 ...................................................................................................................................... 5

3. 布局规范 ................................................................................................................................................. 6 3.1. 3.2. 3.3. 3.5. 3.6. 3.7. 3.8. 3.9.

缩进对齐 .......................................................................................................................................... 6 一行一个语句 .................................................................................................................................. 6 行长度 .............................................................................................................................................. 7 空行 .................................................................................................................................................. 7 空格 .................................................................................................................................................. 8 大括号 .............................................................................................................................................. 9 圆括号 ............................................................................................................................................ 10 布局补充 ......................................................................................................................................... 11

4. 注释规范 ............................................................................................................................................... 12 4.1. 4.2. 4.3. 4.4. 4.5. 4.6.

整体要求 ........................................................................................................................................ 12 块注释 ............................................................................................................................................ 13 单行注释 ........................................................................................................................................ 14 尾端注释 ........................................................................................................................................ 14 类的注释 ........................................................................................................................................ 15 方法注释 ........................................................................................................................................ 15

5. 语句规范 ............................................................................................................................................... 16 5.1. 5.2. 5.3. 5.4. 5.5. 5.6. 5.7.

简单语句 ........................................................................................................................................ 16 复合语句 ........................................................................................................................................ 16 返回语句 ........................................................................................................................................ 17 IF,IF-ELSE,IF ELSE-IF ELSE语句 ................................................................................................ 17 FOR语句 ......................................................................................................................................... 18 WHILE语句 ..................................................................................................................................... 19 DO-WHILE语句 ............................................................................................................................... 19

ii

5.8. SWITCH语句 ................................................................................................................................... 19 5.9. TRY-CATCH语句 ............................................................................................................................. 20 6. 日志规范 ............................................................................................................................................... 21 6.1. 日志记录规范 ................................................................................................................................ 21 7. 异常规范 ............................................................................................................................................... 22 7.1. 捕获的异常:不能忽视 ................................................................................................................ 22 8. 框架规范 ............................................................................................................................................... 23 8.1. APPFRAME框架 .......................................................................................................................... 23 9. 开发约定 ............................................................................................................................................... 24 9.1. 性能优化 ........................................................................................................................................ 24

iii

1. 概述

1.1. 编制说明

为了提升事业部编码工作的规范性,促进产品代码的可读性、可维护性,提升团队协作开发效率,降低各产品线、部门之间研发沟通成本,迫切需要统一的编码规范,用来指导和要求日常的研发工作,因此组织事业部下属各部门技术专家共同制定《移动客户事业部编码规范》。

本规范体系包括Java、C++、Html/CSS、JavaScript、数据库(Oracle)SQL语言以及执行与检查测量分册。

本册对事业部内Java语言的编码规范进行详细阐述。

1.2. 适用范围

亚信Java代码开发人员 亚信代码质量控制人员 亚信设计工程师 亚信测试工程师 亚信PSO

1.3. 参考文档

1. Java官方规范

2. 现有研发中心、区域编码规范 3. 《Google Java Style》

1.4. 术语解释

本文中使用到的专业术语解释如下: 序号 术语 1 驼峰式命名法 解释 驼峰式命名法是程序编写时的一套命名规则,当变量名和函式名称

是由二个或多个单字连结在一起,而构成的唯一识别字时,利用“驼峰式大小写”来表示,可以增加变量和函式的可读性。 驼峰式命名法分大驼峰式命名法(UpperCamelCase)和小驼峰式命名法(lowerCamelCase)。 大驼峰式命名法(upper camel case)每一个单字的首字母都采用大写字母,例如:FirstName、LastName、CamelCase,也被称为 Pascal 命名法。 小驼峰式命名法(lower camel case)第一个单字以小写字母开始,第二个单字的首字母大写。例如:firstName、lastName。 2 K & R 风格 对于非空块和块状结构,大括号遵循Kernighan和Ritchie风格 - - - - 左大括号前不换行 左大括号后换行 右大括号前换行 如果右大括号是一个语句、函数体或类的终止,则右大括号后换行; 否则不换行。例如,如果右大括号后面是else或逗号,则不换行。 示例: return new MyClass() { @Override public void method() { if (condition()) { try { something(); } catch (ProblemException e) { recover(); } } } }; 3 魔术数字 魔术数字(magic number)是程式设计中所谓的直接写在程式码里的具体数值(如“10”,“123”等以数字直接写出的值)。虽然程式作者写的时候自己能了解数值的意义,但对其他程式员而言,甚至制作者本人经过一段时间后,会难以了解这个数值的用途,只能苦笑讽刺“这个数值的意义虽然不懂,不过至少程式会动,真是个魔术般的数字”而得名。 4 CAS机制 CAS,又称Compare-and-Swap,是多线程中实现同步的一种原子指令。拿到一个新值后,CAS将其与内存中的值进行比较,若内存中的值和这个值不一样,则将这个值写入内存,否则,不做操作。

1

2. 命名规范

2.1. 包名

? 规则

1) 包名用公司域名倒置+产品名称/项目名称+模块名称。

2) 包名全部小写,连续的单词只是简单地连接起来,不使用下划线,用有意义的英文名词,禁止使用汉语拼音。

3) 使用完整单词,避免缩写词(除非该缩写词被广泛使用,如URL,HTML)。

示例:

com.ai.crm.res 2.2. 类名

? 规则

1) 类名都以大驼峰风格编写,采用大小写混合的方式,每个单词的首字母大写。 2) 类名选取有意义的代表该类实际含义的名词或名词词组,要求为英文单词,禁止使用汉语拼音。

3) 使用完整单词,避免缩写词(除非该缩写词被广泛使用,如URL,HTML)。

示例:

class Raster; class ImageSprite; class Operator; class URLHandler; ? 建议

1) 对于抽象类,应该使用Abstract前缀。

示例:

2

AbstractDataAccess; 2) 接口命名使用字母“I”开头。

示例:

IDataAccess; 3) 接口的实现类建议以Impl结尾。

示例:

DataAccessImpl; 2.3. 方法名

? 规则

1) 方法名都以小驼峰风格编写,采用大小写混合的方式,第一个单词的首字母小写,其后单词的首字母大写。 2) 方法名通常是动词或动词短语。

示例:

run(); runFast(); getBackground(); 3) 构造函数名称与类名一致,避免在类中有与构造函数相同命名的方法名称。 ? 建议

1) 方法名称命名格式建议如下:

特殊method名称 is+<标识符> 说明 ? 用于判断一个标志位的method。 ? 返回一个布尔值。 ? 用于判断能否执行一个动作。 ? 返回一个布尔值。 ? 用于取得一个属性或一个值。 ? 用于设置一个属性或一个值。 isAlive 举例 can+<标识符> canSleep get+<标识符> set+<标识符> getProperty setProperty

3

2) 成员函数的控制符号要准确,不是必须使用public属性的应该使用

protected,不是必须使用protected的应该使用private.

2.4. 常量名

? 规则

1) 常量名,应该全部大写,单词间用下划线隔开,并用static final修饰词修饰。 2) 常量名通常是名词或名词短语。

示例:

static final int MIN_WIDTH = 4; static final int MAX_WIDTH = 999; static final int GET_THE_CPU = 1; 3) 不允许在代码中使用魔术数字,请定义成常量再使用常量的名称。特殊情况除外,如:for循环中作为计数器值的数字常量-1,0和1。 如使用错误的魔术数字: if (score>100){

doBusiness(); } ? 建议

使用范围广的常量统一放在一个类里面定义。

2.5. 变量名

? 规则

变量名以小驼峰风格编写,必须是名词或名词短语。 ? 建议

1) 一个集合,例如数组或者列表,应该以复数的形式命名。

示例:

customers

4

orderItems 2) 不使用public修饰符定义变量。

3) 如果在实际应用中整个名字太长,可以考虑采用适当的缩写方式。

例如:去掉元音字母,保留辅音字母:用msg代替message,用mgr代替manager。 截取字母的一部分:用prop代替properties,用max代替maximum。

4) 对于一些固定的缩写(如:SQL等),其字母大小写规则按照其固定规则书写。

2.6. 参数名

? 规则

1) 参数名以小驼峰风格编写。 2) 参数应该避免用单个字符命名。

2.7. 局部变量名

? 规则

1) 局部变量名以小驼峰风格编写,比起其它类型的名称,局部变量名可以有更为宽松的缩写,不使用下划线开头,不使用拼音。 2) 避免用单字符进行命名,除了循环变量。

3) 局部变量名称不能与类属性名称以及公有方法参数名称相同。

示例:

float width; //良好的风格 float myWidth; //良好的风格

float _width; //不良的风格(使用下划线开头) float changdu; //不良的风格(使用拼音) ? 建议

尽可能在定义变量的同时初始化该变量(就近原则)。

5

3. 布局规范

3.1. 缩进对齐

? 规则

1) 缩进使用4个空格,不允许使用Tab。 2) 对齐使用空格,不允许使用Tab。

3.2. 一行一个语句

? 规则

1) 一行代码只做一件事情,如只定义一个变量,或只写一条语句(for语句除外)。 2) if、for、while、do、switch等语句自占一行,执行语句不得紧跟其后。不论执行语句有多少都要加{}。

示例a为风格良好的代码行,示例b为风格不良的代码行。

int width; int depth; x=a + b; y = c + d; z = e + f; if (width < height){ dosomething(); } for (initialization; condition; update){ dosomething(); } // 空行 other(); a风格良好的代码行 b风格不良的代码行 for (initialization; condition; update) dosomething(); other(); if (width < height) dosomething(); // 宽度 // 深度 x = a + b; y = c + d; z = e + f; int height; // 高度 int width, height, depth;// 宽度高度深度

6

3.3. 行长度

? 规则

一行80个字符的限制(package、import除外),超过必须换行。 ? 建议

1) 当一个表达式无法容纳在一行内时,可以依据如下规则断开: - 在一个逗号后面断开 - 在一个操作符前面断开

- 新的一行应该与上一行同一级别表达式的开头处对齐

- 如果以上规则导致你的代码混乱或者使你的代码都堆挤在右边,那就代之以缩进4个空格。 示例:

if ((veryLongerVariable1 >= veryLongerVariable12) && (veryLongerVariable3 <= veryLongerVariable14) && (veryLongerVariable5 <= veryLongerVariable16)){ dosomething(); } 3.4. 行数

? 建议

1) 每个Java源文件不超过2000行,太长的程序难以阅读,应该尽量避免。 2) 每个方法建议不要超过120行,最多不超过300行。

3.5. 空行

? 规则

1) 类内连续的成员之间:字段、构造函数、方法、嵌套类、静态初始化块、实例初始化块间需要一个空行。

2) 在每个类/接口声明之后、每个函数定义结束之后都要加空行。参见示例a。

7

3) 在一个函数体内,局部变量定义和方法的第一条语句之间应加空行分隔。参见示例b。

4) 在一个函数体内,在两个逻辑段之间应加空行分隔。参见示例b。 5) 在块注释或单行注释之前,都要加空行。参见示例a。

// 空行 /*

*Here is a block comment. */

void Function1(…){ … } // 空行

void Function2(…){ … } // 空行

void Function3(…){ … }

// 空行

while (condition){ int var1; int var2; // 空行 statement1; // 空行

if (condition) { } // 空行 statement4; }

statement2; statement3;

}else{

示例a函数之间的空行 示例b函数内部的空行

? 建议

允许使用多个空行,但是如果无法提升代码可读性的话就不建议使用。

3.6. 空格

? 规则

1) 关键字之后要留空格。如abstract、static、final、case 等关键字之后至少要留一个空格,否则无法辨析关键字。如if、for、while等关键字之后应留一个空格再跟左括号‘(’,以突出关键字。 2) ‘)’与之后的‘{’之间保留一个空格。

3) 函数名之后不要留空格,紧跟左括号‘(’,以与关键字区别。 4) ‘(’向后紧跟,‘)’、‘,’、‘;’向前紧跟,紧跟处不留空格。 5) ‘,’之后要留空格,如function(x, y, z)。

8

6) 如果‘;’不是一行的结束符号,其后要留空格,如for (initialization; condition; update)。

7) 赋值操作符、比较操作符、算术操作符、逻辑操作符、位域操作符,如“=”、“+=”、“>=”、“<=”、“+”、“*”、“%”、“&&”、“||”、“<<”、“^”等二元操作符的前后应当加空格。

8) 一元操作符如“!”、“~”、“++”、“--”等前后不加空格。 9) 像“[]”、“.”这类操作符前后不加空格。

示例:

void func1(int x, int y, int z); // 良好的风格 if (year >= END_YEAR) // 良好的风格 if ((a>=b) && (c<=d)) // 良好的风格 for (i =0; i

id func1 (int x,int y,int z);// 不良的风格 if(year>=END_YEAR) // 不良的风格 if(a>=b&&c<=d) // 不良的风格 for(i=0;i<10;i++) // 不良的风格 for (i = 0; I < 10; i ++) //过多的空格 x=a

? 规则

1) 大括号与if、 else、 for、do、while语句一起使用时,即使只有一条语句(或是空),也应该把大括号写上。 2) 非空块:K & R 风格

对于非空块和块状结构,大括号遵循Kernighan和Ritchie风格: - 左大括号前不换行 - 左大括号后换行 - 右大括号前换行

9

- 如果右大括号是一个语句、函数体或类的终止,则右大括号后换行; 否则不换行。例如,如果右大括号后面是else或逗号,则不换行。 示例:

return new MyClass() { @Override public void method() { if (condition()) { try { something(); } catch (ProblemException e) { recover(); } } } };

3) 空块:可以用简洁版本

一个空的块状结构里什么也不包含,大括号可以简洁地写成{},不需要换行。例外:如果它是一个多块语句的一部分(if/else 或 try/catch/finally) ,即使大括号内没内容,右大括号也要换行。 示例:

void doNothing() {} try { something(); } catch (ProblemException e) { } finally{ }

3.8. 圆括号

? 建议

在含有多种运算符的表达式中要使用圆括号来避免运算符优先级问题。 示例:

if (a == b && c == d) // 不推荐 if ((a == b) && (c == d)) // 推荐

10

3.9. 布局补充

? 规则

1) 每次只声明一个变量,不要使用组合声明,比如int a, b

2) 使用非C风格的数组声明,中括号是类型的一部分:String[] args, 而非String args[]。 ? 建议 3) 枚举类

当枚举常量比较多的时候(行字符个数超过80个)建议换行。

由于枚举类也是一个类,因此所有适用于类的格式规则也适用于枚举类。 4) 需要时才声明,并尽快进行初始化

不要在一个代码块的开头把局部变量一次性都声明了(这是c语言的做法),而是在第一次需要使用它时才声明。 局部变量在声明时最好就进行初始化,或者声明后尽快进行初始化。 5) 注解(Annotations)

注解紧跟在文档块后面,应用于类、方法和构造函数,一个注解独占一行。 例如:

@Override @Nullable public String getNameIfPresent() { ... }

11

4. 注释规范

4.1. 整体要求

? 规则

注释按 JavaDoc 的注释规范来写。 ? 建议

1) 建议注释行不少于源程序的1/3。 2) 尽量用代码本身而不是注释来阐述。

示例:

// Check to see if the employee is eligible for full benefits if ((employee.flags & HOURLY_FLAG) && (employee.age > 65)) 可调整为:

if (employee.isEligibleForFullBenefits()) 3) 原则上不允许存在注释掉的代码。

示例:

/*A a = new B(); // System.out.println(\B b = new B();*/ 4) 代码中待实现的地方推荐使用//TODO注释,需修正或优化、完善的地方推荐使用//FIXME注释,并在注释符号后写明具体内容。 5) 对于以下情况需要写注释: ? 具有特殊处理意义的 ? 按常规不能理解的 ? 上下文相关的 ? 能帮助快速理解代码 示例:

帮助快速理解代码:

12

// 以配置为优先,未配的情况下通过表中记录计算序列起始值。 int start = JefConfiguration.getInt(Item.AUTO_SEQUENCE_START, -1); if (start == -1) { start = (StringUtils.isNotBlank(tableName) && } StringUtils.isNotBlank(columnName)) ? meta.getSequenceStartValue(schema, tableName, columnName, null) : DEFAULT_SEQ_START; 阐明意图:

if (dbs.isEmpty()) { //当第一个库且没有名称时,容错,默认创建一个名称 ... } 警示:

// Don't run unless you have some time to kill. public void testWithReallyBigFile() { writeLinesToFile(10000000); response.setBody(testFile); } response.readyToSend(this); assertSubString(\, responseString); assertTrue(bytesSent > 1000000000); String responseString = output.toString(); 4.2. 块注释

1) 块注释与其周围的代码在同一缩进级别。它们可以是/* ... */风格,也可以是// ...风格。对于多行的/* ... */注释,后续行必须从*开始, 并且与前一行的*对齐。 示例1:

/* * This is * okay. */ 示例2:

// And so // is this. 示例3:

/* Or you can

13

* even do this. */ 2) 注释不要封闭在由星号或其它字符绘制的框架里。 以下注释方式不符合规范:

/***************************** *这样注释不符合规范 * ******************************/ 4.3. 单行注释

? 规则

1) 单行注释以“//”开头,后跟注释内容。

2) 短注释可以显示在一行内,并与其后的代码具有一样的缩进层级。如果一个注释不能在一行内写完,就该采用块注释(参见\块注释\。单行注释之前应该有一个空行。 示例:

if (condition) { // Handle the condition. ... } 4.4. 尾端注释

? 建议

极短的注释可以与它们所要描述的代码位于同一行,但是应该有足够的空白来分开代码和注释。

以下是一个Java代码中尾端注释的例子:

if (a == 2) { return TRUE;// special case } else { return isPrime(a);// works only for odd a }

14

4.5. 类的注释

? 规则

采用JavaDoc能够识别的格式。具体格式如下(未注明 optional 的均为必须具有):

/** * 类简述 *

* 类说明、详细描述(optional) *

* * @Company * @Copyright * @author (公司email) * @version (optional) * @since (optional) * @see (optional) * @CreateDate${date} */ 4.6. 方法注释

? 规则

方法头部注释采用JavaDoc能够识别的格式。 示例:

/** * 功能简述 *

* 详细描述(可选) *

* @param 参数1参数1类型参数1说明 * @param 参数2参数2类型参数2说明 * @return 返回值 * @exception 异常1,异常2... *

* 修改记录:(日期,修改人,描述) (可选) *

*/

15

? 建议

方法体对应注释如下:

private static void methodName() { // 1、do step 1 doStep1(); // 2、do step 2 doStep2(); // start modify, XXX, 1999-6-1 //此处写修改内容注释 doBusiness(); // end modify, XXX, 1999-6-1 doOthers(); } 此处写修改记录注释,修改记录两端要用start modify 和end modify另加修改人名和修改日期括起,并需要加注修改内容。

5. 语句规范

引用静态成员变量时使用类名引用, 使用非静态成员变量时应该使用this引用。

5.1. 简单语句

? 规则

1) 每行只包含一条语句

示例:

argv++; // 正确 argc--; // 正确 argv++; argc--; // 不正确 5.2. 复合语句

复合语句是包含在大括号中的语句序列,如\语句 }\。

16

? 规则

1) 包括在其中的语句应缩进一个层次。

2) 左大括号\应位于复合语句起始行的行尾;右大括号\应另起一行并与复合语句首行对齐。

5.3. 返回语句

? 规则

带有表达式的return语句,表达式要用小括号\括起来,使返回值更为显见。 示例:

return (size ? size : defaultSize); 5.4. if,if-else,if else-if else语句

? 规则

1) 采用K & R 风格,if-else语句应该具有如下格式:

if (condition) { statements; } if (condition) { statements; } else { statements; } if (condition) { statements; } else if (condition) { statements; } else{ statements; }

2) if语句总是用\和\括起来,这样可以防止书写失误。

17

if (width < height) { dosomething(); } 示例a风格良好的代码行示例b风格不良的代码行

if (width < height) dosomething();

3) 避免在判断语句中字符和整型变量的直接比较,要显式地进行类型转换。

示例:

char a =’a’; if (SCORE_NUMBER == Interger.valueOf(a)) 而不是写成:

if (SCORE_NUMBER== a) ? 建议

1) 在判断语句中,尽量将常量写在左值,而不是右值

示例:

if (0 == count) // 即使写成0 = count也能在编译期发现 而不是写成:

if (count == 0) // 如果写成count = 0则不容易发现问题 2) 对多条件的判断语句,每个条件语句和子条件要用上括号。

示例:

if( (0 == a) && ((SCORE_NUMBER == b) || (c == d)) ) 5.5. for语句

? 规则

1) 一个for语句应该具有如下格式:

for (initialization; condition; update) { statements; } 2) 在for语句的初始化(initialization)或更新子句(update),避免使用三个以上变量而导致复杂度提高。若需要,可以在for循环之前(为初始化子句)或for循环末尾(为更新子句)使用单独的语句。

18

5.6. while语句

? 规则

一个while语句应该具有如下格式

while (condition){ statements; } 5.7. do-while语句

? 规则

一个do-while语句应该具有如下格式:

do { statements; } while (condition); 5.8. switch语句

? 规则

1) 一个switch语句应该具有如下格式:

switch (condition) { case ABC: statements1; /* falls through */ case DEF: statements2; break; case XYZ: statements3; break; default: statements4; break; }

19

2) 每当一个case顺着往下执行时,若没有break语句,应在break语句的位置添加注释。上面的示例代码中就包含注释/* falls through */。

5.9. try-catch语句

? 规则

代码中通过try/catch捕捉异常,catch所捕捉的异常顺序必须遵循类派生相反顺序,否则将会导致部分异常无法捕捉或捕捉处理的代码错误。

20

6. 日志规范

6.1. 日志记录规范

? 规则

1) 禁止使用System.out.println()来记录日志;而是使用Logger或Log4J来记录。

示例: 错误的输出:

System.out.println(\+ listCaBillProds.size()); 正确的输出: if (log.isDebugEnabled()) { log.debug(\+ listCaBillProds.size()); } 2) 为不同日志消息选择不同级别, INFO(提示类)、DEBUG(调试类)、ERROR(错误类)。

3) 在输出日志时先进行级别判断,

示例:

if (logger.isDebuggable()){ logger.debug(...); }

21

7. 异常规范

7.1. 捕获的异常:不能忽视

? 规则

1) 捕获的异常需要处理,如果不需要在catch块中做任何响应,需要做注释加以说明。 示例: try{ inti=Integer.parseInt(response); returnhandleNumericResponse(i); }catch(NumberFormatExceptionok){ // it's not numeric; that's fine, just continue } returnhandleTextResponse(response); ? 建议

1) 在Java程序中,当出错的时候推荐使用异常处理机制,而不是使用Return Code。 2) 推荐使用自定义Exception,用来补充Java的Exception类。每个工程,都应该整理出通用的Exception在最外层予以统一处理。自定义的Exception视具体的应用情况继承不同的Exception,如:EOFException,IOException等。不推荐直接继承Exception类。

3) 由于Exception机制占用系统资源较高,并且会危害编译器的分析性能,所以不

要依赖异常进行业务逻辑控制,禁止滥用Exception。

22

8. 框架规范

8.1. APPFRAME框架

详见附件《NGCRM技术开发规范》

23

9. 开发约定

9.1. 性能优化

? 建议

1) 线程安全的情况下,使用StringBuilder替代StringBuffer,前者速度快。 2) 判断空串,使用if(str == null || str.length() == 0) 替代 if(str== null || \,前者效率高。

另推荐使用org.apache.commons.lang.StringUtils.isBlank(str),因为和if(str == null || str.length() == 0){}等价,但可读性和简洁性更好; 取反的方法StringUtils.isNotBlank(str)。

注意,StringUtils中方法 isBlank 和 isEmpty 的区别如下: StringUtils.isBlank (\StringUtils.isEmpty(\

3) 新增实体,内置类型推荐使用原子类型,原子类型不需要判断null、不需要装箱、占内存少,如int优于Integer。

4) if、else if的组合超过3个else if,考虑使用switch进行替代,效率有所提升。

不推荐的用法:

if (Constant.PAY_METHOD_CASH == payIn.getPayMethod()) { // 现金缴费 busiSpecId = busiSpecManager.getBusiSpecId(BusiType.PAYMENT_CASH); } else if (Constant.PAY_METHOD_CHECK == payIn.getPayMethod()) { // 支票缴费 busiSpecId = busiSpecManager.getBusiSpecId(BusiType.PAYMENT_CHECK); } else if (Constant.PAY_METHOD_CASH_CHECK == payIn.getPayMethod()) { // 现金+支票缴费 busiSpecId = busiSpecManager.getBusiSpecId(BusiType.PAYMENT_CASH_CHECK); } else if (Constant.PAY_METHOD_BANKCARD == payIn.getPayMethod()) { // 银行卡缴费 busiSpecId = busiSpecManager.getBusiSpecId(BusiType.PAYMENT_BANKCARD); } else if (Constant.PAY_METHOD_MOVE_POS == payIn.getPayMethod()) { // 移动POS缴费 busiSpecId = busiSpecManager.getBusiSpecId(BusiType.PAYMENT_MOVE_POS);

24

} else { throw new BusinessException(ErrorCode.PAY_METHOD_IS_ERROR, payIn.getPayMethod()); } 推荐的用法: switch (payIn.getPayMethod()) { case Constant.PAY_METHOD_CASH: // 现金缴费 case Constant.PAY_METHOD_CHECK: // 支票缴费 case Constant.PAY_METHOD_CASH_CHECK: // 现金+支票缴费 case Constant.PAY_METHOD_BANKCARD: // 银行卡缴费 case Constant.PAY_METHOD_MOVE_POS: // 移动POS缴费 default: } throw new BusinessException(ErrorCode.PAY_METHOD_IS_ERROR, payIn.getPayMethod()); busiSpecId = busiSpecManager.getBusiSpecId(BusiType.PAYMENT_MOVE_POS); break; busiSpecId = busiSpecManager.getBusiSpecId(BusiType.PAYMENT_BANKCARD); break; busiSpecId = busiSpecManager.getBusiSpecId(BusiType.PAYMENT_CASH_CHECK); break; busiSpecId = busiSpecManager.getBusiSpecId(BusiType.PAYMENT_CHECK); break; busiSpecId = busiSpecManager.getBusiSpecId(BusiType.PAYMENT_CASH); break; 5) 返回值为list、map、set类型的,返回空数据结构替代返回null。 推荐的写法:

public List queryBill(Long acctId, Integer billMonth) { if (acctId == null || billMonth == null) { // 类似的还有Collections.emptyMap()、Collections.emptySet() return Collections.emptyList(); } ... return list; } 6) 与循环变量无关的逻辑,放在循环体之外。

25

错误的写法:

for(int i=0, n = list.size(); i< n; i++){ CaBill caBill = new CaBill(); caBill.setBillFee(list.get(i)); Date stsDate = DateUtils.getCurrentDate(); caBill.setStsDate(stsDate); list.add(caBill); } 推荐的写法: Date stsDate = DateUtils.getCurrentDate(); for (int i = 0, n = list.size(); i < n; i++) { CaBill caBill = new CaBill(); caBill.setBillFee(list.get(i)); caBill.setStsDate(stsDate); list.add(caBill); }

7) list删除元素,使用迭代器遍历;

for循环优于while循环,迭代器变量作用范围更小。 推荐的写法:

List strList = new ArrayList(); for (Iterator iter = strList.iterator(); iter.hasNext(); ) { String str = iter.next(); iter.remove(); } 8) map的遍历,使用entitySet迭代器效率较高; for循环优于while循环,迭代器变量作用范围更小。 推荐的写法:

Map map = new HashMap(); map.put(\, \); map.put(\, new Integer(1)); // JDK 1.4 for (Iterator> iter = map.entrySet().iterator(); iter.hasNext(); ) { Entry item = iter.next(); String key = item.getKey(); Object value = item.getValue(); }

26

// JDK 1.5 for (Map.Entry item : map.entrySet()) { String key = item.getKey(); Object value = item.getValue(); } 9) 慎用ThreadLocal的资源。

如果使用的话,一定要注意线程变量的回收,以免由于线程池的使用而造成一个线程跑多笔业务,线程变量重复使用,导致潜在的风险。 错误示例:

public class TestService{ public static ThreadLocal threadVal = new ThreadLocal(); public void serviceMethod() { } ... Integer threadInt = TestService.threadVal.get(); testAction.doSomething(); // finish service // 错误的原因是threadVal未回收(threadVal.remove) }

10) 与log4j有关的性能问题 - Logger对象定义的标准方式: private static transient Logger log = Logger.getLogger(CreateIndex.class);

static: 防止每次构造业务对象时都连带构造一个Logger 对象,Logger 的创建成本较高,

设置成static 后,在后续创建业务对象时能节省几十毫秒开销。 transient: 防止Logger 对象被序列化,占用序列化开销。 11) 与字符串有关的性能问题

- 尽量不要使用java.lang.String中提供的split,replace,replaceAll等方法 原因:

JDK当中是用正则表达式来做匹配的,在频繁使用的场景下,对性能影响很大。

27

替代方案:

使用org.apache.commons.lang.StringUtils中提供的split,replaceChars,性能是JDK实现的3-4倍。

- 用StringBuilder替代StringBuffer

原因:StringBuilder提供的函数是不加锁的,而StringBuffer是加锁的。业务侧代码,绝大部分场景下都无需加锁。

- 在大量字符串拼接时用StringBuilder,避免使用“...” + “...” + “...” - 虽然用了StringBuilder,但没发挥StringBuilder的优点。 错误的使用方式:

StringBuilder sb = new StringBuilder(); sb.append(“111” + “222” + “333”); // 还是在做字符串+ 操作! sb.append(“444” + “555” + “666”); 正确的使用方式:

StringBuilder sb = new StringBuilder(); sb.append(“111”); sb.append(“222”); sb.append(“333”); sb.append(“444”); sb.append(“555”); sb.append(“666”); - 在构造StringBuilder时,要能预估容量就更好。 比如:

StringBuilder sb = new StringBuilder(20); sb.append(“111”); sb.append(“222”); sb.append(“333”); sb.append(“444”); sb.append(“555”); sb.append(“666”); 原因:防止StringBuilder因预先分配的容量不够而做二次扩充。 12) 与for循环有关的性能问题 - 避免条件判断时调用函数 错误的方式:

for (int i = 0; i < datas.size(); i++) 正确的方式:

28

for (int i = 0, size = datas.size(); i < size; i++) - try...catch要放在循环外面 错误的方式:

for (...) { try { ... } catch (Exception e) { ... } } 正确的方式:

try { for (...) { ... } } catch (Exception e) { ... } - 避免在循环中反复调用同一个结果集的同一个对象 错误的方式:

for (int i = 0; i < datas.size(); i++) { String discntCode = datas.getData(i).getString(“DISCNT_CODE”); String discntName = datas.getData(i).getString(“DISCNT_NAME”); String discntExplain = datas.getData(i).getString(“DISCNT_EXPLAIN”); ... } 正确的方式:

for (int i = 0, size = datas.size(); i < size; i++) { IData data = datas.getData(i); String discntCode = data.getString(“DISCNT_CODE”); String discntName = data.getString(“DISCNT_NAME”); String discntExplain = data.getString(“DISCNT_EXPLAIN”); ... } 13) 与集合类有关的性能问题

- 能用ArrayList就不要用Vector 原因:能不加锁就不加锁。

- 能用HashMap就不要用Hashtable

29

原因:能不加锁就不加锁。

- 能用HashMap就不要用ConcurrentHashMap 原因:能不加锁就不加锁。

- 用ConcurrentHashMap替代Collections.synchronizedMap(new HashMap());

原因:控制锁的粒度尽可能小,前者是多个细粒度的局部锁,后者是一把全局锁。 - 在使用容器时能预设容量,尽量预设 比如:

new ArrayList(30); // 注意,够用就好,不要设置得过大! new HashMap(30); // 注意,够用就好,不要设置得过大!

原因:防止基于数组实现的ArrayList二次扩充和HashMap的重hash。 14) 与开关有关的性能问题

- 不论是框架开关,还是业务开关,到java端后最好保存为boolean型。 错误的方式:

if (“true”.equals(validate)) { ... } 正确的方式:

if (validate) { ... } 前者开销是后者的几十倍,字符串越长,开销越大。 15) 与工具方法有关的性能问题 - 将小工具函数标识为final 示例:

public static final boolean isBlank (String str) { if (null == str || “”.equals(str.trim())) { return true; } return false; } 原因:JDK在运行一定次数后,JIT有可能将此final类型的函数内联。 16) 与SQL动态绑定有关的性能问题

30

能用PreparedStatement就不要使用Statement 推荐的方式:

PreparedStatement stmt = conn.prepareStatement(“select TD_M_ASYNCTASK WHERE LOG_ID = ?”); stmt.setString(1, “10000000085005”); stmt.executeQuery(); 不推荐的方式:

Statement stmt = conn.createStatement(); stmt.execute(“select * TL_M_ASYNCTASK_LOG WHERE LOG_ID = ‘” + logID + “’”); 两者的性能差距就是编译型语言与脚本语言的差距。 17) 与反射调用有关的性能问题

尽可能缓存Method对象,获取Method对象是反射调用最消耗性能的地方。 18) 缓存使用的性能问题 缓存的作用有两个:

- 将需要的数据搬到更近的地方。 - 缓存计算结果。

避免从缓存获取数据后,再对数据进行排序、过滤等操作。

正确的做法是,先排序好,过滤完再放进缓存,以后直接拿来用即可。 19) 并发锁带来的性能问题

- 最好是不用锁,比如用CAS机制解决并发问题。 正确的计数器写法:

private static AtomicInteger count = new AtomicInteger(); public void xxx() { ... // 业务处理 count.getAndIncrement(); // 计数器递增 } 错误的计数器写法:

private static int count = 0; public static synchronize int increment() { ... // 业务处理 return count++; // 计数器递增 } - 在读多写少的并发场景,用读写锁,不要用排它锁,如synchronize。 20) 杂项

31

- 避免频繁使用instanceof做类型判断,建议拆成多个对象,用多态调用。 - 正则表达式比较灵活,但在特定场景下性能不一定最优。

- 避免对象的反复构造,可以复用就复用,尤其是大对象的构造,是非常消耗性能的。

- 两数组对拷,记得用System.arraycopy(),不要自己写for循环,性能差距非常大。

32

本文来源:https://www.bwwdw.com/article/0kv6.html

Top