- 浏览: 33504 次
- 性别:
- 来自: 上海
1 排版规范
.1 规则
1. *程序块要采用缩进风格编写,缩进的空格数为4个。
说明:对于由开发工具自动生成的代码可以有不一致。
2. *分界符(如大括号‘{’和‘}’)应各独占一行并且位于同一列,同时与引用它们的语句左对齐。在函数体的开始、类和接口的定义、以及if、for、do、while、switch、case语句中的程序都要采用如上的缩进方式。
示例:如下例子不符合规范。
for (...) {
... // program code
}
if (...)
{
... // program code
}
void example_fun( void )
{
... // program code
}
应如下书写。
for (...)
{
... // program code
}
if (...)
{
... // program code
}
void example_fun( void )
{
... // program code
}
3. *较长的语句、表达式或参数(>80字符)要分成多行书写,长表达式要在低优先级操作符处划分新行,操作符放在新行之首,划分出的新行要进行适当的缩进,使排版整齐,语句可读。
示例:
if (filename != null
&& new File(logPath + filename).length() < LogConfig.getFileSize())
{
... // program code
}
public static LogIterator read(String logType, Date startTime,
Date endTime, int logLevel, String userName, int bufferNum)
4. *不允许把多个短语句写在一行中,即一行只写一条语句
示例:如下例子不符合规范。
LogFilename now = null; LogFilename that = null;
应如下书写
LogFilename now = null;
LogFilename that = null;
5. *if, for, do, while, case, switch, default 等语句自占一行,且if, for, do, while等语句的执行语句无论多少都要加括号{}。
示例:如下例子不符合规范。
if(writeToFile) writeFileThread.interrupt();
应如下书写:
if(writeToFile)
{
writeFileThread.interrupt();
}
6. *相对独立的程序块之间、变量说明之后必须加空行。
示例:如下例子不符合规范。
if(log.getLevel() < LogConfig.getRecordLevel())
{
return;
}
LogWriter writer;
应如下书写
if(log.getLevel() < LogConfig.getRecordLevel())
{
return;
}
LogWriter writer;
int index;
7. *对齐只使用空格键,不使用TAB键。
说明:以免用不同的编辑器阅读程序时,因TAB键所设置的空格数目不同而造成程序布局不整齐。JBuilder、UltraEdit等编辑环境,支持行首TAB替换成空格,应将该选项打开。
8. *在两个以上的关键字、变量、常量进行对等操作时,它们之间的操作符之前、之后或者前后要加空格;进行非对等操作时,如果是关系密切的立即操作符(如.),后不应加空格。
说明:采用这种松散方式编写代码的目的是使代码更加清晰。
由于留空格所产生的清晰性是相对的,所以,在已经非常清晰的语句中没有必要再留空格,如果语句已足够清晰则括号内侧(即左括号后面和右括号前面)不需要加空格,多重括号间不必加空格,因为在Java语言中括号已经是最清晰的标志了。
在长语句中,如果需要加的空格非常多,那么应该保持整体清晰,而在局部不加空格。给操作符留空格时不要连续留两个以上空格。
示例:
(1) 逗号、分号只在后面加空格。
int a, b, c;
(2)比较操作符, 赋值操作符"="、 "+=",算术操作符"+"、"%",逻辑操作符"&&"、"&",位域操作符"<<"、"^"等双目操作符的前后加空格。
if (current_time >= MAX_TIME_VALUE)
a = b + c;
a *= 2;
a = b ^ 2;
(3)"!"、"~"、"++"、"--"、"&"(地址运算符)等单目操作符前后不加空格。
flag = !isEmpty; // 非操作"!"与内容之间
i++; // "++","--"与内容之间
(4)"."前后不加空格。
p.id = pid; // "."前后不加空格
(5) if、for、while、switch等与后面的括号间应加空格,使if等关键字更为突出、明显。
if (a >= b && c > d)
.2 建议
1. 类属性和类方法不要交叉放置,不同存取范围的属性或者方法也尽量不要交叉放置。
格式:
类定义
{
类的公有属性定义
类的保护属性定义
类的私有属性定义
类的公有方法定义
类的保护方法定义
类的私有方法定义
}
2 注释规范
A. 规则
1. 一般情况下,源程序有效注释量必须在30%以上。
说明:注释的原则是有助于对程序的阅读理解,在该加的地方都加了,注释不宜太多也不能太少,注释语言必须准确、易懂、简洁。可以用注释统计工具来统计。
2. 包的注释:包的注释写入一个名为 package.html 的HTML格式的说明文件放入当前路径。
说明:方便JavaDoc收集
示例:
com/huawei/iin/websmap/comm/package.html
3. 包的注释内容:简述本包的作用、详细描述本包的内容、产品模块名称和版本、公司版权。
说明:在详细描述中应该说明这个包的作用以及在整个项目中的位置。
格式:
<html>
<body>
<p>一句话简述。
<p>详细描述。
<p>产品模块名称和版本
<br>公司版权信息
</body>
</html>
示例:
<html>
<body>
<P>为 WEBSMAP 提供通信类,上层业务使用本包的通信类与 SMP-B 进行通信。
<p>详细描述。。。。。。。。
<p>IIN V100R001 WEBSMAP
<br>(C) 版权所有 2000-2001 华为技术有限公司
</body>
</html>
4. 文件注释:文件注释写入文件头部,包名之前的位置。
说明:注意以 /* 开始避免被 JavaDoc 收集
示例:
/*
* 注释内容
*/
package com.huawei.iin.websmap.comm;
5. 文件注释内容:版权说明、描述信息、生成日期、修改历史。
说明:文件名可选。
格式:
/*
* 文件名:[文件名]
* 版权:〈版权〉
* 描述:〈描述〉
* 修改人:〈修改人〉
* 修改时间:YYYY-MM-DD
* 跟踪单号:〈跟踪单号〉
* 修改单号:〈修改单号〉
* 修改内容:〈修改内容〉
*/
说明:每次修改后在文件头部写明修改信息,CheckIn的时候可以直接把蓝色字体信息粘贴到VSS的注释上。在代码受控之前可以免去。
示例:
/*
* 文件名:LogManager.java
* 版权:Copyright 2000-2001 Huawei Tech. Co. Ltd. All Rights Reserved.
* 描述: WIN V200R002 WEBSMAP 通用日志系统
* 修改人: 张三
* 修改时间:2001-02-16
* 修改内容:新增
* 修改人: 李四
* 修改时间:2001-02-26
* 跟踪单号:D20103
* 修改单号:WSS368
* 修改内容:。。。。。。
* 修改人: 王五
* 修改时间:2001-03-25
* 跟踪单号:D27153
* 修改单号:WSS498
* 修改内容:。。。。。。
*/
6. 类和接口的注释:该注释放在 package 关键字之后,class 或者 interface 关键字之前。
说明:方便JavaDoc收集
示例:
package com.huawei.iin.websmap.comm;
/**
* 注释内容
*/
public class CommManager
7. 类和接口的注释内容:类的注释主要是一句话功能简述、功能详细描述,
说明:可根据需要列出:版本号、生成日期、作者、内容、功能、与其它类的关系等。 如果一个类存在Bug,请如实说明这些Bug。
格式:
/**
* 〈一句话功能简述〉
* 〈功能详细描述〉
* @author [作者]
* @version [版本号, YYYY-MM-DD]
* @see [相关类/方法]
* @since [产品/模块版本]
* @deprecated
*/
说明:描述部分说明该类或者接口的功能、作用、使用方法和注意事项,每次修改后增加作者和更新版本号和日期,@since 表示从那个版本开始就有这个类或者接口,@deprecated 表示不建议使用该类或者接口。
示例:
/**
* LogManager 类集中控制对日志读写的操作。
* 全部为静态变量和静态方法,对外提供统一接口。分配对应日志类型的读写器,
* 读取或写入符合条件的日志纪录。
* @author 张三,李四,王五
* @version 1.2, 2001-03-25
* @see LogIteraotor
* @see BasicLog
* @since CommonLog1.0
*/
8. 类属性、公有和保护方法注释:写在类属性、公有和保护方法上面。
示例:
/**
* 注释内容
*/
private String logType;
/**
* 注释内容
*/
public void write()
9. 成员变量注释内容:成员变量的意义、目的、功能,可能被用到的地方。
10. 公有和保护方法注释内容:列出方法的一句话功能简述、功能详细描述、输入参数、输出参数、返回值、违例等。
格式:
/**
* 〈一句话功能简述〉
* 〈功能详细描述〉
* @param [参数1] [参数1说明]
* @param [参数2] [参数2说明]
* @return [返回类型说明]
* @exception/throws [违例类型] [违例说明]
* @see [类、类#方法、类#成员]
* @deprecated
*/
说明:@since 表示从那个版本开始就有这个方法;@exception或throws 列出可能仍出的异常;@deprecated 表示不建议使用该方法。
示例:
/**
* 根据日志类型和时间读取日志。
* 分配对应日志类型的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)
11. 对于方法内部用throw语句抛出的异常,必须在方法的注释中标明,对于所调用的其他方法所抛出的异常,选择主要的在注释中说明。 对于非RuntimeException,即throws子句声明会抛出的异常,必须在方法的注释中标明。
说明:异常注释用@exception或@throws表示,在JavaDoc中两者等价,但推荐用@exception标注Runtime异常,@throws标注非Runtime异常。异常的注释必须说明该异常的含义及什么条件下抛出该异常。
12. *注释应与其描述的代码相近,对代码的注释应放在其上方或右方(对单条语句的注释)相邻位置,不可放在下面,如放于上方则需与其上面的代码用空行隔开。
13. *注释与所描述内容进行同样的缩排。
说明:可使程序排版整齐,并方便注释的阅读与理解。
示例:如下例子,排版不整齐,阅读稍感不方便。
public void example( )
{
// 注释
CodeBlock One
// 注释
CodeBlock Two
}
应改为如下布局。
public void example( )
{
// 注释
CodeBlock One
// 注释
CodeBlock Two
}
14. *将注释与其上面的代码用空行隔开。
示例:如下例子,显得代码过于紧凑。
//注释
program code one
//注释
program code two
应如下书写:
//注释
program code one
//注释
program code two
15. *对变量的定义和分支语句(条件分支、循环语句等)必须编写注释。
说明:这些语句往往是程序实现某一特定功能的关键,对于维护人员来说,良好的注释帮助更好的理解程序,有时甚至优于看设计文档。
16. *对于switch语句下的case语句,如果因为特殊情况需要处理完一个case后进入下一个case处理,必须在该case语句处理完、下一个case语句前加上明确的注释。
说明:这样比较清楚程序编写者的意图,有效防止无故遗漏break语句。
17. *边写代码边注释,修改代码同时修改相应的注释,以保证注释与代码的一致性。不再有用的注释要删除。
18. *注释的内容要清楚、明了,含义准确,防止注释二义性。
说明:错误的注释不但无益反而有害。
19. *避免在注释中使用缩写,特别是不常用缩写。
说明:在使用缩写时或之前,应对缩写进行必要的说明。
B. 建议
1. *避免在一行代码或表达式的中间插入注释。
说明:除非必要,不应在代码或表达中间插入注释,否则容易使代码可理解性变差。
2. *通过对函数或过程、变量、结构等正确的命名以及合理地组织代码的结构,使代码成为自注释的。
说明:清晰准确的函数、变量等的命名,可增加代码可读性,并减少不必要的注释。
3. *在代码的功能、意图层次上进行注释,提供有用、额外的信息。
说明:注释的目的是解释代码的目的、功能和采用的方法,提供代码以外的信息,帮助读者理解代码,防止没必要的重复注释信息。
示例:如下注释意义不大。
// 如果 receiveFlag 为真
if (receiveFlag)
而如下的注释则给出了额外有用的信息。
// 如果从连结收到消息
if (receiveFlag)
4. *在程序块的结束行右方加注释标记,以表明某程序块的结束。
说明:当代码段较长,特别是多重嵌套时,这样做可以使代码更清晰,更便于阅读。
示例:参见如下例子。
if (...)
{
program code1
while (index < MAX_INDEX)
{
program code2
} // end of while (index < MAX_INDEX) // 指明该条while语句结束
} // end of if (...) // 指明是哪条if语句结束
5. *注释应考虑程序易读及外观排版的因素,使用的语言若是中、英兼有的,建议多使用中文,除非能用非常流利准确的英文表达。
说明:注释语言不统一,影响程序易读性和外观排版,出于对维护人员的考虑,建议使用中文。
6. 方法内的单行注释使用 //。
说明:调试程序的时候可以方便的使用 /* 。。。*/ 注释掉一长段程序。
7. 注释尽量使用中文注释和中文标点。方法和类描述的第一句话尽量使用简洁明了的话概括一下功能,然后加以句号。接下来的部分可以详细描述。
说明:JavaDoc工具收集简介的时候使用选取第一句话。
8. 顺序实现流程的说明使用1、2、3、4在每个实现步骤部分的代码前面进行注释。
示例:如下是对设置属性的流程注释
//1、 判断输入参数是否有效。
。。。。。
// 2、设置本地变量。
。。。。。。
9. 一些复杂的代码需要说明。
示例:这里主要是对闰年算法的说明。
//1. 如果能被4整除,是闰年;
//2. 如果能被100整除,不是闰年.;
//3. 如果能被400整除,是闰年.。
3 命名规范
A. 规则
1. 包名采用域后缀倒置的加上自定义的包名,采用小写字母。在部门内部应该规划好包名的范围,防止产生冲突。部门内部产品使用部门的名称加上模块名称。产品线的产品使用产品的名称加上模块的名称。
格式:
com.huawei.产品名.模块名称
com.huawei.部门名称. 项目名称
示例:
融合WEBSMAP包名 com.huawei.iin.websmap
通用消息转发包名 com.huawei.insa2.msgtrans
2. 类名和接口使用类意义完整的英文描述,每个英文单词的首字母使用大写、其余字母使用小写的大小写混合法。
示例:OrderInformation, CustomerList, LogManager, LogConfig, SmpTransaction
3. 方法名使用类意义完整的英文描述:第一个单词的字母使用小写、剩余单词首字母大写其余字母小写的大小写混合法。
示例:
private void calculateRate();
public void addNewOrder();
4. 方法中,存取属性的方法采用setter 和 getter方法,动作方法采用动词和动宾结构。
格式:
get + 非布尔属性名()
is + 布尔属性名()
set + 属性名()
动词()
动词 + 宾语()
示例:
public String getType();
public boolean isFinished();
public void setVisible(boolean);
public void show();
public void addKeyListener(Listener);
5. 属性名使用意义完整的英文描述:第一个单词的字母使用小写、剩余单词首字母大写其余字母小写的大小写混合法。属性名不能与方法名相同。
示例:
private customerName;
private orderNumber;
private smpSession;
6. 常量名使用全大写的英文描述,英文单词之间用下划线分隔开,并且使用 final static 修饰。
示例:
public final static int MAX_VALUE = 1000;
public final static String DEFAULT_START_DATE = "2001-12-08";
7. 属性名可以和公有方法参数相同,不能和局部变量相同,引用非静态成员变量(放在堆中,分配给对象的,对象的修改不会影响其他对象的该变量值)时使用 this (this指向当前对象)引用,引用静态成员变量(相当于全局变量,在类加载时就放入静态存储空间中;针对一个类,无论该类生成多少个对象,在全局中只有一个,任一个对象修改都会影响全局)时使用类名引用。
示例:
public class Person
{
private String name;
private static List properties;
public void setName (String name)
{
this.name = name;
}
public void setProperties (List properties)
{
Person.properties = properties;
}
B. 建议
1. 常用组件类的命名以组件名加上组件类型名结尾。
示例:
Application 类型的,命名以App 结尾——MainApp
Frame 类型的,命名以Frame 结尾——TopoFrame
Panel 类型的,建议命名以Panel 结尾——CreateCircuitPanel
Bean 类型的,建议命名以Bean 结尾——DataAccessBean
EJB 类型的,建议命名以EJB 结尾——DBProxyEJB
Applet 类型的,建议命名以Applet 结尾——PictureShowApplet
2. 如果函数名超过15 个字母,可采用以去掉元音字母的方法或者以行业内约定俗成的缩写方式缩写函数名。
示例:getCustomerInformation() 改为 getCustomerInfo()
3. 准确地确定成员函数的存取控制符号,不是必须使用 public 属性的,请使用 protected,不是必须使用 protected, 请使用 private。
示例: protected void setUserName(), private void calculateRate()
4. 含有集合意义的属性命名,尽量包含其复数的意义。
示例:customers, orderItems
4 编码规范
A. 规则
1. *明确方法功能,精确(而不是近似)地实现方法设计。一个函数仅完成一件功能,即使简单功能也应该编写方法实现。
说明:虽然为仅用一两行就可完成的功能去编方法好象没有必要,但用方法可使功能明确化,增加程序可读性,亦可方便维护、测试。
2. 应明确规定对接口方法参数的合法性检查应由方法的调用者负责还是由接口方法本身负责,缺省是由方法调用者负责。
说明:对于模块间接口方法的参数的合法性检查这一问题,往往有两个极端现象,即:要么是调用者和被调用者对参数均不作合法性检查,结果就遗漏了合法性检查这一必要的处理过程,造成问题隐患;要么就是调用者和被调用者均对参数进行合法性检查,这种情况虽不会造成问题,但产生了冗余代码,降低了效率。
3. 明确类的功能,精确(而不是近似)地实现类的设计。一个类仅实现一组相近的功能。
说明:划分类的时候,应该尽量把逻辑处理、数据和显示分离,实现类功能的单一性。
示例:
数据类不能包含数据处理的逻辑。
通信类不能包含显示处理的逻辑。
4. 所有的数据类必须重载toString() 方法,返回该类有意义的内容。
说明: 父类如果实现了比较合理的toString() ,子类可以继承不必再重写。
示例:
public TopoNode
{
private String nodeName;
public String toString()
{
return "NodeName : " + nodeName;
}
}
5. 数据库操作、IO操作等需要使用结束close()的对象必须在try -catch-finally 的finally中close()。
示例:
try
{
// ... ...
}
catch(IOException ioe)
{
//... ...
}
finally
{
try
{
out.close();
}
catch (IOException ioe)
//... ...
}
}
6. 异常捕获后,如果不对该异常进行处理,则应该纪录日志或者ex.printStackTrace() 。
说明:若有特殊原因必须用注释加以说明。
示例:
try
{
//.... ...
}
catch (IOException ioe)
{
ioe.printStackTrace ();
}
7. 自己抛出的异常必须要填写详细的描述信息。
说明:便于问题定位。
示例:
throw new IOException("Writing data error! Data: " + data.toString());
8. 运行期异常使用RuntimeException的子类来表示,不用在可能抛出异常的方法声明上加throws子句。非运行期异常是从Exception继承而来的,必须在方法声明上加throws子句。
说明:
非运行期异常是由外界运行环境决定异常抛出条件的异常,例如文件操作,可能受权限、磁盘空间大小的影响而失败,这种异常是程序本身无法避免的,需要调用者明确考虑该异常出现时该如何处理方法,因此非运行期异常必须有throws子句标出,不标出或者调用者不捕获该类型异常都会导致编译失败,从而防止程序员本身疏忽。
运行期异常是程序在运行过程中本身考虑不周导致的异常,例如传入错误的参数等。抛出运行期异常的目的是防止异常扩散,导致定位困难。因此在做异常体系设计时要根据错误的性质合理选择自定义异常的继承关系。
还有一种异常是Error 继承而来的,这种异常由虚拟机自己维护,表示发生了致命错误,程序无法继续运行例如内存不足。我们自己的程序不应该捕获这种异常,并且也不应该创建该种类型的异常。+
9. 在程序中使用异常处理还是使用错误返回码处理,根据是否有利于程序结构来确定,并且异常和错误码不应该混合使用,推荐使用异常。
说明:
一个系统或者模块应该统一规划异常类型和返回码的含义。
但是不能用异常来做一般流程处理的方式,不要过多地使用异常,异常的处理效率比条件分支低,而且异常的跳转流程难以预测。
10. *注意运算符的优先级,并用括号明确表达式的操作顺序,避免使用默认优先级。
说明:防止阅读程序时产生误解,防止因默认的优先级与设计思想不符而导致程序出错。
示例:
下列语句中的表达式
word = (high << | low (1)
if ((a | b) && (a & c)) (2)
if ((a | b) < (c & d)) (3)
如果书写为
high << 8 | low
a | b && a & c
a | b < c & d
(1)(2)虽然不会出错,但语句不易理解;(3)造成了判断条件出错。
11. *避免使用不易理解的数字,用有意义的标识来替代。涉及物理状态或者含有物理意义的常量,不应直接使用数字,必须用有意义的静态变量来代替。
示例:如下的程序可读性差。
if (state == 0)
{
state = 1;
... // program code
}
应改为如下形式:
private final static int TRUNK_IDLE = 0;
private final static int TRUNK_BUSY = 1;
private final static int TRUNK_UNKNOWN = -1;
if (state == TRUNK_IDLE)
{
state = TRUNK_BUSY;
... // program code
}
12. 数组声明的时候使用 int[] index ,而不要使用 int index[] 。
说明:使用int index[] 格式使程序的可读性较差
示例:
如下程序可读性差:
public int getIndex()[]
{
....
}
如下程序可读性好:
public int[] getIndex()
{
....
}
13. 调试代码的时候,不要使用 System.out 和 System.err 进行打印,应该使用一个包含统一开关的测试类进行统一打印。
说明:代码发布的时候可以统一关闭调试代码,定位问题的时候又可以打开开关。
14. 用调测开关来切换软件的DEBUG版和正式版,而不要同时存在正式版本和DEBUG版本的不同源文件,以减少维护的难度。
B. 建议
1. 记录异常不要保存exception.getMessage(),而要记录exception.toString()。
示例:NullPointException抛出时常常描述为空,这样往往看不出是出了什么错。
2. 一个方法不应抛出太多类型的异常。
说明: 如果程序中需要分类处理,则将异常根据分类组织成继承关系。如果确实有很多异常类型首先考虑用异常描述来区别,throws/exception子句标明的异常最好不要超过三个。
3. 异常捕获尽量不要直接 catch (Exception ex),应该把异常细分处理。
4. *如果多段代码重复做同一件事情,那么在方法的划分上可能存在问题。
说明:若此段代码各语句之间有实质性关联并且是完成同一件功能的,那么可考虑把此段代码构造成一个新的方法。
5. 对于创建的主要的类,最好置入main()函数,包含用于测试那个类的代码 。
说明:主要类包括:
1、能完成独立功能的类,如通讯。
2、具有完整界面的类,如一个对话框、一个窗口、一个帧等。
3、JavaBean 类。
示例:
public static void main(String[] arguments)
{
CreateCircuitDialog circuitDialog1 = new CreateCircuitDialog (null, "Ciruit", false);
circuitDialog1.setVisible(true);
}
6. 集合中的数据如果不使用了应该及时释放,尤其是可重复使用的集合。
说明:由于集合保存了对象的句柄,虚拟机的垃圾收集器就不会回收。
7. *源程序中关系较为紧密的代码应尽可能相邻。
说明:便于程序阅读和查找。
示例:矩形的长与宽关系较密切,放在一起。
rect.length = 10;
rect.width = 5;
8. *不要使用难懂的技巧性很高的语句,除非很有必要时。
说明:高技巧语句不等于高效率的程序,实际上程序的效率关键在于算法。
5 JTEST规范
A. 规则(1-2 级)
1. 在switch 中每个 case 语句都应该包含 break 或者 return 。
示例:
switch(weekOneDay)
{
case 1:
System.out.println("Monday");
break;
case 2:
System.out.println("Tuesday");
break;
case 3:
System.out.println("Wednesday");
break;
default:
System.out.println("Sorry I don't know");
}
我的本意只输出“Monday”但是如果去掉第一个Break,输出的结果为:
Monday
Tuesday
2. 不要使用空的for 、if 、while 语句。
3. 在运算中不要减小数据的精度。
下面是不正确示例:
double d1 = 1.0000002d;
double d2 = 0.0000002;
System.out.println(d1-d2);
打印结果为0.9999999999999999
4. switch 语句中的 case 关键字要和后面的常量保持一个空格,switch 语句中不要定义case 之外的无用标签。
5. 不要在if 语句中使用等号= 进行赋值操作。
说明:使用if(a=b)编译不能通过,但是if (a = = (b = e xpress))是可以编译通过的,但是不推荐使用
示例:
if (a = = (b = e xpress)) //其中等号“= =”与赋值“=”操作符容易混淆
{
//语句
6. 静态成员或者方法使用类名访问,不使用句柄访问。
说明:不要使用创建的实例(或this、super)访问,而直接使用类名访问这样读者一看到就知道这个方法或属性是静态的(因为类只能直接访问静态的属性或方法,不能直接访问非静态属性或方法)。
7. 方法重载的时候,一定要注意方法名相同,避免类中使用两个非常相似的方法名。
说明:方法重载的时候如果方法名不相同即它们不存在重载关系,一个类中存在几个非常相似方法名这样使得程序可读性差。
重载只关注方法名、参数类型、个数相同,不关注返回类型。
8. 不要在ComponentListener.componentResized() 方法中调用 setResize() 方法。
说明:ComponentListener为一个接口,该接口是用来监听"组件"的尺寸变化事件,当"组件"的尺寸发生更改,setResize()方法就会调用该接口的componentResized方法,如果在componentResized方法中调用setResize()方法会造成死循环
9. 不要覆盖父类的静态方法和私有方法。
说明:静态方法和私有方法不能被继承,子类实现不了覆盖,只能属于重写该方法。
覆盖父类的静态方法和私有方法实现不了多态,下面是覆盖静态方法的示例:
class Father
{
public static void print()
{
System.out.println("father静态方法");
}
}
public class Son extends Father
{
public static void print()
{
System.out.println("other静态方法");
}
public static void main(String[] args)
{
Father intance = new Son()
intance.print();
}
打印的结果为“father静态方法”。在类外部访问不了私有方法,所以实现不了覆盖多态。
10. 不要覆盖父类的属性。
说明:属性不对外提供访问(不会提供public权限),只私有属性不能被继承,属性的重写无意义
11. 不要使用两级以上的内部类。
说明:嵌套太多,1容易出错,2不容易理解
12. 去掉接口中多余的定义(不使用 public, abstract, static, final 等,这是接口中默认的)。
说明:接口是抽象方法和常量的定义的集合。
示例:
public interface Runner //public是一定要写,否则限制了访问权限
{
int id = 1; //默认是public static final int id=1;
void run (); //默认是public void run();
}
其中id是常量,run是抽象方法。
13. 不要定义不会被用到的局部变量、类私有属性、类私有方法和方法参数。
14. 显式初始化所有的静态属性。
一般使用静态属性之前不会对静态属性赋值,而是直接用类访问静态属性,
如果你没初始化他的默认值为0;
static(定义的属性在内存中只有一份拷贝)在类载入的时候就会被初始化,可以被修改。如果没有显示初始化,系统会给个默认值
15. 不要使用 System.getenv() 方法。
建议不要使用'System.getenv ()
不建议使用'System.getenv ()',这个方法看起来很好用,不过并不是所有的系统都有环境变量的。
不用这个方法也可能带来一些不方便。错误示例:
void method (String name) {
System.getenv (name); // 可以用其他方法来代替
}
如果不用这个方法,我们可以用其它的方法来代替。比如:'System.getProperty ()’,'getTypeName ()'等,
这也可以找到java的系统属性。
16. 不要硬编码 ‘\n’和‘\r’作为换行符号。
不要使用’\n’或者'\r'来分行
这两个标记看来很普遍,特别是’\n’。我们经常用来作为分行用。但是不同的系统用不同的分行字符,
所以这些字符在某些意义上违背了java的平台无关性。
错误示例:
System.out.println("Hello\n" + name);
我们可以用其它的一些方法来代替,比如println(),这个方法在不同的系统平台上都起到相同的作用。
后者推荐大家用这个方法:System.getProperty("line.separator")
17. 不要直接使用 java.awt.peer.* 里面的接口。
该包在现有的1.4.2的JDK中无法查到
18. 使用 System.arraycopy() ,不使用循环来复制数组。
19. 避免不必要的 instanceof 比较运算和类造型运算。
20. 不要在 finalize() 方法中删除监听器(Listeners)。
不要在finalize()方法中删除Listeners,finalize()只有再没有对象引用的时候调用,如果Listeners从finalize()方法中去除了,被finalize的对象将不会再垃圾收集中去除。
Public void finalize() throws Throwable{
BButton removeActionListener(act);
}
21. 在 finalize() 方法中一定要调用 super.finalize() 方法
如果没有调用super.finalize()只执行本类中的finalize(),即不会执行Object中的finalize();
这里的finalize ()是java在进行垃圾收集的时候调用的,和finally不一样。如果你的父类没有定义finally()的话,你也应该调用。
这里有两个原因:
1)在不改变代码的情况下能够将父类的finally方法加到你的类中。
2)以后你会养成习惯调用父类的finally方法,即使父类没有定义finally方法的时候。
正确的方法应该如此:
public class parentFinalize {
protected void finalize () throws Throwable {
super.finalize(); // FIXED
}
22. 在 finalize() 方法中的 finally 中调用 super.finalize() 方法。
为了确保在程序不管有没有出现异常的情况下都能执行super.finalize()
finally 再异常处理时提供 finally 块来执行任何清除操作。如果抛出一个异常,那么相匹配的 catch 子句就会执行,然后控制就会进入 finally 块(如果有的话)。finalize 方法名。Java 技术允许使用 finalize() 方法在垃圾收集器将对象从内存中清除出去之前做必要的清理工作。这个方法是由垃圾收集器在确定这个对象没有被引用时对这个对象调用的。它是在 Object 类中定义的, 因此所有的类都继承了它。子类覆盖 finalize() 方法以整理系统资源或者执行其他清理工作。finalize() 方法是在垃圾收集器删除对象之前对这个对象调用的。
23. 进行字符转换的时候应该尽可能的较少临时变量。
24. 使用ObjectStream 的方法后,调用reset() ,释放对象。
25. 线程同步中,在循环里面使用条件测试(使用 while(isWait) wait() 代替 if(isWait) wait())。
26. 不掉用 Thread 类的 resume(), suspend(), stop() 方法。
说明:会导致死锁发生。
虽然stop可以避免死锁发生。在程序运行的过程中如果停止可能会导致数据的不一致性。
27. 减小单个方法的复杂度,使用的 if, while, for, switch 语句要在10个以内。
28. 在Servlets中,重用JDBC连接的数据源。
节省系统资源
29. 减少在Sevlets中使用的同步方法。
说明:Sevlets本身是已多线程的方式响应多个用户的请求。如果多个用户都要调用同一个同步方法,这个时候只能响应一个用户。
30. 不定义在包中没有被用到的友好属性、方法和类。
友好属性的访问控制权限是在一个包中,在一个包中如果不用那定义他是多余的。
31. 没有子类的友好类应该定义成 final 。
32. 没有被覆盖的友好方法应该定义成 final 。
如果一个类被声明为final,意味着它不能再派生出新的子类,不能作为父类被继承。
因此一个类不能既被声明为 abstract的,又被声明为final的。将变量或方法声明为final,可以保证它们在使用中不被改变。被声明为final的变量必须在声明时给定初值,而在以后的引用中只能读取,不可修改。被声明为final的方法也同样只能使用,不能重载
B. 建议(3级或以上)
1. 为 switch 语句提供一个 default 选项。
请参看:规则1,在没有符合case 条选项件的情况下default 选项给用户提供友好的信息。
2. 不要在 for 循环体中对计数器的赋值。
3. 不要给非公有类定义 public 构建器。
说明:定义成非公有类访问控制权限,这样难以控制程序-,还有在同一个文件中定义了多个公有类编译会失败。
4. 不要对浮点数进行比较运算,尤其是不要进行 ==, !=运算,减少 >, < 运算。
两个不等的浮点数进行“==”比较有可能比较的结果是相等的。
5. 实现 equals() 方法时,先用 getClass() 或者 instanceof 进行类型比较,通过后才能继续比较。
首先两个对象先用getClass()获取它们所属的类,再用instanceof看这两个对象是不属于同一个类,如果不是,就不用equals()比较了。
6. 不要重载 main() 方法用作除入口以外的其他用途。
7. 方法的参数名不要和类中的方法名相同。
编译不会出错,这样会程序可读性更差
8. 除了构建器外,不要使用和类名相同的方法名。
会使读者把那个不是构造器的函数与构造函数混淆。编译不会出错
9. 不要定义 Error 和 RuntimeException 的子类,可以定义 Exception 的子类。
error 表示恢复不是不可能但很困难的情况下的一种严重问题。比如说内存溢出。不可能指望程序能处理这样的情况。
exception 表示一种设计或实现问题。也就是说,它表示如果程序运行正常,从不会发生的情况。
Huxiaoyong 细化
10. 线程中需要实现 run() 方法。
说明:创建线程有两种方法,继承Thread类和实现Runnable接口。
后者无疑是要实现的,前者如果你不覆盖Thread中的run()方法什么事都不干,这样创建的线程是无意义的。
11. 使用 equals() 比较两个类的值是否相同。
“==”操作符用于比较两个变量(包括基本类型与引用类型变量)的值是否相同,equals()方法用于比较两个对象(注意:这里只能是引用类型变量)的内容是否相同。
java虚拟机用创建对象的内存地址(内存区)付给前面声明的变量。
例如 String s = new String("hello");这个语句是把对象new String("hello")的内存地址付给s,即现在变量s指向系统为对象new String("hello")分配的内存地址(内存区);
其实变量s真正的值为对象new String("hello")的内存地址(内存区);
在java中也有指针,只是java让指针对程序员不可见,即程序员不可以控制指针。
示例:
public class comp
{
public comp()
{
}
public void weatherEquals()
{
String s1 = "hello";
String s2 = "hello";
//操作符“=”右边的步骤:先创建一个内容为“hello”的对象,再返回这个对象的内 //存地址给s3;所以s3的值为这个对象内存地址
String s3 = new String("hello");
String s4 = new String("hello");
if (s1==s2)
{
//这里相等,是因为编译器会做优化工作, 发现S2的内容根S1一样,编译器就将 //s2的"指针"指向s1指向的内存
System.out.println("s1与s2是指向同一个对象的内存区");
}
else
{
System.out.println("s1与s2不是指向同一个对象的内存区");
}
if(s1.equals(s2))
{
System.out.println("s1与s2所指向对象的内容相同");//对象的内容是指对象的某个或某些属性值
}
else
{
System.out.println("s1与s2所指向对象的内容不相同");
}
if(s3==s4)
{
System.out.println("s3与s4是指向同一个对象的内存区");
}
else
{
//这里不是指向同一个对象,是因为你手工指定jvm用new去分配两块内存, 所以需 //要从内存块的角度来理解
System.out.println("s3与s4不是指向同一个对象的内存区");
}
if(s3.equals(s4))
{
System.out.println("s3与s4所指向对象的内容相同");
}
else
{
System.out.println("s3与s4所指向对象的内容不相同");
}
}
public static void main(String[] args)
{
comp comp1 = new comp();
/*下面执行结果为:
s1与s2是指向同一个对象的内存区
s1与s2所指向对象的内容相同
s3与s4不是指向同一个对象的内存区
s3与s4所指向对象的内容相同
*/
comp1.weatherEquals();
}
}
12. 字符串和数字运算结果相连接的时候,应该把数字运算部分用小括号括起来。
说明:如果你没用括号括起来,先会把数字转换为字符串再与已有的字符串相连,
例如:
int iNumber1 = 2;
int iNumber2 = 3;
String sString1 = "nhao" + iNumber1 + iNumber2;
String sString2 = "nhao" + (iNumber1 + iNumber2);
System.out.println(sString1);
System.out.println(sString2);
前一个打印语句的结果为“nihao23”,后一个为"nihao5";
13. 类中不要使用非私有(公有、保护和友好)的非静态属性。
14. 在类中对于没有实现的接口,应该定义成抽象方法,类应该定义成抽象类。(5级)
说明:因为继承接口要实现其中的所有抽象方法。继承抽象类可以不用实现其中所有抽象方法。
15. 不要显式导入 java.lang.* 包;
java会默认的导入java.lang包中的所有类。所以你没有必要再导入这个包。
16. 初始化时不要使用类的非静态属性。
说明:你用一个非静态属性去初始化一个变量,有可能非静态属性自己本身还没有初始化。
17. 显式初始化所有的局部变量。
因为没有初始化的字段会是一个潜在的bug,如一个整数开始你不能确定什么值就初始化一个0给它。
所以最好初始化类里面的所有的字段。特别是静态的字段,最好在一开始就分配一个初始值
错误示例:
public class CSI {
public CSI () {
this (12);
k = 0;
}
public CSI (int val) {
j = val;
}
private int i = 5;
private int j;
private int k;
}
正确示例:
public class CSIFixed {
public CSIFixed () {
this (12);
}
public CSIFixed (int val) {
j = val;
k = 0;
}
private int i = 5;
private int j;
private int k;
}
18. 按照方法名把方法排序放置,同名合同类型的方法应该放在一起。
19. 不要使用嵌套赋值,即在一个表达式中使用多个 = 。
20. 不要在抽象类的构建器中调用抽象方法。
21. 重载 equals() 方法的同时,也应该重载 hashCode() 方法。
每一个存在内存中的实例的hashcode()返回码是不同的,通常可能需要在equals()方法中判断两个引用指向的是不是同一个对象,这是就需要比较hashcode了
Huxiaoyong 细化
22. 工具类(Utility)不要定义构建器,包括私有构建器。
这是一种软件设计思想,工具类通常都是设计成单例类,没有必要允许用户创建多个实例
23. 不要在 switch 中使用10个以上的 case 语句。
24. 把 main() 方法放在类的最后。
25. 声明方法违例的时候不要使用 Exception ,应该使用它的子类。
Exeption报的异常没有它的子类具体。例如,DataFormatException,如果出异常就知道是数据格式异常。 IOException,就知道是IO操作的异常。
26. 不要直接扔出一个Error ,应该扔出它的子类。
error 表示恢复不是不可能但很困难的情况下的一种严重问题。比如说内存溢出。不可能指望程序能处理这样的情况。
exception 表示一种设计或实现问题。也就是说,它表示如果程序运行正常,从不会发生的情况。 子类更具体
27. 在进行比较的时候,总是把常量放在同一边(都放在左边或者都放在右边)。
28. 在可能的情况下,总是为类定义一个缺省的构建器。
说明:没有定义一个缺省的构建器,但定义了有一个参数的构造器,这个缺省的构建器就不存在了。那么它的子类的构造器没有指定调用它的某个构造器程序就会编译失败。
29. 在捕获违例的时候,不使用 Exception, RuntimeException, Throwable,尽可能使用它们的子类。
说明:它们的子类报的异常更具体,即让你更清楚知道是什么异常。
30. 在接口或者工具类中中定义常量。(5级)
31. 使用大写‘L’表示 long 常量。(5级)
说明:长整常量的时候,用L来代替l.
因为l很容易和数字1混一起。
错误示例:
long temp = 23434l;
正确示例:
long temp = 23434L;
32. main() 方法必须是 public static void main(String[]arg)。(5级)
说明:由于Java虚拟机需要调用类的main()方法,所以该方法的访问权限必须是public,又因为Java虚拟机在执行main()方法时不必创建对象,所以该方法必须是static的。该方法接收一个String类型的数组参数,该数组中保存执行Java命令时传递给所运行的类参数。
33. 对返回类型为 boolean 的方法使用 is 开头,其它类型的不能使用。
34. 对非boolean类型取值方法(getter)使用 get 开头,其它类型的不能使用。
35. 对于设置值的方法(setter)使用 set 开头,其它类型的不能使用。
36. 方法需要有同样数量参数的注释 @param。
37. 不要在注释中使用不支持的标记,如:@unsupported 。
38. 不要使用 Runtime.exec() 方法。
在本程序进程的过程中启动另一个进程。
例如:
try
{
java.lang.Runtime.getRuntime().exec("mspaint");
}catch (Exception e)
{
}
启动微软的画图软件。
39. 不要自定义本地方法(native method)。
java代码调用其他语言的代码,例如System中
public static native void arraycopy(Object src, int srcPos, Object dest, int destPos,int length);
Huxiaoyong 细化
40. 使用尽量简洁的运算符号。
41. 使用集合时设置初始容量。
说明:集合类是无边界的。 在创建集合对象时java会默认分配一段空间给它,默认的空间可能过大,这样就浪费空间。在程序运行过程中可能默认的空间不够java又要重新创建一个集合对象这样浪费时间,
42. 单个首字符的比较使用 charAt() 而不用 startsWith() 。
43. 对于被除数或者被乘数为2的n次方的乘除运算使用移位运算符 >>, << 。
44. 一个字符的连接使用‘ ’而不使用 “ ”,如:String a = b + 'c'。
''字符是基本的数据类型,""是引用数据类型,基本数据运算的效率更高。
45. 不要在循环体内调用同步方法和使用 try-catch 块。
While(i<10)
{
Try
{
}
Catch(Exception e)
{
}
}
上述代码的问题就是当有异常抛出时不是结束循环体,而是让循环体继续循环.
46. 不要使用不必要的布尔值比较,如:if (a.equals(b)), 而不是 if (a.equals(b)==true)。
47. 常量字符串使用 String, 非常量字符串使用 StringBuffer 。
String 的内容是不可变,StringBuffer的内容是可变;
示例:
48. 在循环条件判断的时候不要使用复杂的表达式。
49. 对于“if (condition) do1; else do2;”语句使用条件操作符“if (condition)?do1:do2;”。
50. 不要在循环体内定义变量。
for循环体中是用堆栈对定义的变量分配空间,即每次循环定义的变量占用的内存空间不同,在定义变量的时候又要发费时间,这样既浪费空间又浪费时间。
51. 使用StringBuffer的时候设置初始容量。
在创建StringBuffer对象时java会默认分配一段空间给它,默认的空间可能过大,这样就浪费空间。在程序运行过程中可能默认的空间不够java又要重新创建一个StringBuffer这样浪费时间,
52. 尽可能的使用局部变量进行运算。
变量的作用域过大这是一个隐患的Bug,可能你在运行这段程序的时候而被另一段改变这个变量值而导致程序错误运行。
53. 尽可能少的使用 ‘!’操作符。(5级)
54. 尽可能的对接口进行 instanceof 运算。(5级)
55. 不要使用 Date[] 而要使用 long[] 替代。
基本类型数据运算效率更高
56. 不要显式调用 finalize() 。
虽然显式的调用这个方法可以使你确保你的调用,但是当这个方法收集了以后垃圾收集会再收集一次。需要确保这个方法只执行一次
57. 不要使用静态集合,其内存占用增长没有边界。
58. 不要重复调用一个方法获取对象,使用局部变量重用对象。
说明:运行方法效率低,直接用变量引用对象效率更高。
下面是错误的示例:
Runtime.getRuntime().exec("mspaint");
Runtime.getRuntime().exec("notepad");
.............
下面是正确的示例:
Runtime run = Runtime.getRuntime();
run. exec("mspaint");
run. Exec("notepad");
................
59. 线程同步中,使用 notifyAll() 代替 notify()。
60. 避免在同步方法中调用另一个同步方法造成的死锁。
示例:
class A
{
synchronized void foo(B b)
{
try
{
Thread.sleep(1000);
}
catch(Exception e)
{
System.out.println(e.getMessage());
}
b.last();
}
synchronized void last()
{
System.out.println("inside a.last");
}
}
class B
{
synchronized void bar(A a)
{
try
{
Thread.sleep(1000);
}
catch(Exception e)
{
System.out.println(e.getMessage());
}
a.last();
}
synchronized void last()
{
System.out.println("inside b.last");
}
}
public class Deadlock implements Runnable
{
A a = new A();
B b = new B();
Deadlock()
{
new Thread(this).start();
a.foo(b);
}
public void run()
{
b.bar(a);
}
public static void main(String args[])
{
new Deadlock();
System.out.println("end");
}
}
在上述程序用sleep来强制foo和bar这两个同步方法出现死锁;
在类A中同步方法foo调用B类同步方法last,在类B中同步方法bar调用A类同步方法laster而出现死锁
61. 非同步方法中不能调用 wait() , notify() 方法。
62. 使用 wait(), notify() 代替 while(), sleep() 。
sleep()方法是使线程停止一段时间的方法。在sleep 时间间隔期满后,线程不一定立即恢复执行。这是因为在那个时刻,其它线程可能正在运行而且没有被调度为放弃执行,除非(a)“醒来”的线程具有更高的优先级(b)正在运行的线程因为其它原因而阻塞。wait()是线程交互时,如果线程对一个同步对象x 发出一个wait()调用,该线程会暂停执行,被调对象进入等待状态,直到被唤醒或等待时间到。
63. 不要使用同步方法,使用同步块。(5级)
64. 把所有的公有方法定义为同步方法。 (5级)
65. 实现的 Runnable.run() 方法必须是同步方法。 (5级)
66. 一个只有abstract方法、final static 属性的类应该定义成接口。
67. 在 clone() 方法中应该而且必须使用 super.clone() 而不是 new 。
new只是显示的初始一个对象(对象内部数据都为初始值),而clone()是创建一个和现有对象实例完全相同的对象,(clone对象中数据和当当前对象数据完全相同)
68. 常量必须定义为 final 。
69. 在 for 循环中提供终止条件。
70. 在 for, while 循环中使用增量计数。
71. 使用 StringTokenizer 代替 indexOf() 和 substring() 。
72. 不要在构建器中使用非 final 方法。
73. 不要对参数进行赋值操作。(5级)
74. 不要通过名字比较两个对象的类,应该使用 getClass() 。
75. 安全:尽量不要使用内部类。
使所有的内部类"private".Java允许一个类包含另外一个类,但是Java byte code没有这个概念。类被编译器解释成package-private类。内部类能访问外部类的属性,如果内部类能被随意访问, 外部类的属性也能被随意访问。
错误示例:
public class INNER {
class INNER_Class {
void setValue(int i) {
_value = i; // 现在包就可以访问了
}
}
private int _value;
}
所以需要加上private class INNER_Class
76. 安全:尽量不要使类可以克隆。
77. 安全:尽量不要使接口可以序列化。
如果一个字节数组包含了一个被序列化的对象。攻击者就能读到这个对象的内部状态合字段(包括private的)。
错误示例:
public interface sample extends java.io.Serializable
78. 安全:尽量不要使用友好方法、属性和类。
79. Servlet:不要使用 java.beans.Beans.instantiate() 方法。
80. Servlet:不再使用HttpSession时,应该尽早使用 invalidate() 方法释放 。
81. Servlet:不再使用JDBC资源时,应该尽早使用 close() 方法释放 。
82. Servlet:不要使用Servlet的 SingleThreadModel,会消耗大量资源。
83. 国际化:不要使用一个字符进行逻辑操作,使用 Characater。
一个单个字符的前后不要用逻辑操作符,如果代码要在一个国家环境中运行的话。我们可以使用字符比较方法,
这些方法使用统一字符比较标准来定义字符的属性的。
错误示例:public class CLO {
public boolean isLetter (char ch) {
boolean _isLetter = ( ch >= 'a' && ch <= 'z') //错误
|| (ch >= 'A' && ch <= 'Z');
return _isLetter;
}
}
正确示例:
public class CLOFixed {
public boolean isLetter (char ch) {
boolean _isLetter = Character.isLetter(ch);
return _isLetter;
}
}
84. 国际化:不要进行字符串连接操作,使用MessageFormat 。
85. 国际化:不要使用 Date.toString() ,Time.toString() 方法。
不要使用'Date.toString ()'方法,日期格式对于地区和语言不同的国家来说是不一样的,务必不要使用。'DateFormat'类提供了一个预定义的格式类型来指定本地的格式。
错误示例:
public void printToday () {
Date today = new Date ();
String todayStr = today.toString ();
System.out.println (todayStr);
}
正确示例:
public void printToday () {
Locale currentLocale = Locale.getDefault ();
DateFormat dateFormatter = DateFormat.getDateInstance (
DateFormat.DEFAULT, currentLocale);
Date today = new Date ();
String todayStr = dateFormatter.format (today);
System.out.println (todayStr);
}
因为时间的格式各个国家也不一样。如果你使用日期格式类,你的应用就能够在世界上各个地方正确的显示时间和日期了。首先,用'getTimeInstance ()'方法创建一个formatter。然后,调用'format ()'方法。
错误示例:
public class TTS {
public void printTime (Time t1) {
String timeStr = t1.toString ();
System.out.println (timeStr);
}
}
正确示例:
import java.sql.Time;
import java.text.DateFormat;
import java.util.Locale;
public class TTSFixed {
public void printTime (Time t1) {
DateFormat timeFormatter = DateFormat.getTimeInstance(
DateFormat.DEFAULT, Locale.getDefault ());
String timeStr = timeFormatter.format(t1);
System.out.println (timeStr);
}
}
86. 国际化:字符和字符串常量应该放在资源文件中。
87. 国际化:不要使用数字的 toString() 方法。
在全球化的开发中,不要对数字变量使用'toString ()'方法,这个对于java.lang.Number的任何子类都适用。
包括:BigDecimal, BigInteger, Byte, Double, Float, Integer, Long, and Short.
对于这样的情况,java里也定义了"NumberFormat"方法来格式化。
错误示例:
public class NTS {
public void method (Double amount) {
String amountStr = amount.toString ();
System.out.println (amountStr);
}
}
正确示例:
public class NTSFixed {
public void method (Double amount) {
Locale currentLocale = Locale.getDefault ();
NumberFormat numberFormatter =
NumberFormat.getNumberInstance (currentLocale);
String amountStr = numberFormatter.format (amount); //
System.out.println (amountStr + ' ' + currentLocale.toString ());
}
}
88. 国际化:不要使用 StringBuffer , StringTokenizer类。
89. 国际化:不要使用 String 类的 compareTo(), equals() 方法。
建议不要使用'String.equals ()'方法,因为在统一字符比较标准中不一定按照相关的顺序来比较。 'Collator'提供的预定义整理规则来排序string,Collator类调用'getInstance ()'方法,一般来说,可以为默认的本地创建一个Collator。例如:Collator myCollator = Collator.getInstance (); 创建Collator的时候你也可以指定一个特殊的locale。 例如:Collator myFrenchCollator = Collator.getInstance (Locale.FRENCH); 然后就可以调用'Collator.compare ()'来执行一个本地的字符比较myCollator.compare (s1,s2);
错误示例:
public class SE {
public boolean compstr (String s1, String s2) {
boolean b = (s1.equals (s2));
return b;
}
}
正确示例:
public class SEFixed {
public boolean compstr (String s1, String s2) {
Collator myCollator = Collator.getInstance ();
boolean b = (myCollator.compare(s1,s2) == 0);
return b;
}
}
90. 复杂度:建议的最大规模:
继承层次 5层
类的行数 1000行(包含{})
类的属性 10个
类的方法 20个
类友好方法 10个
类私有方法 15个
类保护方法 10个
类公有方法 10个
类调用方法 20个
方法参数 5个
return语句 1个
方法行数 30行
方法代码 20行
注释比率 30%~50%
.1 规则
1. *程序块要采用缩进风格编写,缩进的空格数为4个。
说明:对于由开发工具自动生成的代码可以有不一致。
2. *分界符(如大括号‘{’和‘}’)应各独占一行并且位于同一列,同时与引用它们的语句左对齐。在函数体的开始、类和接口的定义、以及if、for、do、while、switch、case语句中的程序都要采用如上的缩进方式。
示例:如下例子不符合规范。
for (...) {
... // program code
}
if (...)
{
... // program code
}
void example_fun( void )
{
... // program code
}
应如下书写。
for (...)
{
... // program code
}
if (...)
{
... // program code
}
void example_fun( void )
{
... // program code
}
3. *较长的语句、表达式或参数(>80字符)要分成多行书写,长表达式要在低优先级操作符处划分新行,操作符放在新行之首,划分出的新行要进行适当的缩进,使排版整齐,语句可读。
示例:
if (filename != null
&& new File(logPath + filename).length() < LogConfig.getFileSize())
{
... // program code
}
public static LogIterator read(String logType, Date startTime,
Date endTime, int logLevel, String userName, int bufferNum)
4. *不允许把多个短语句写在一行中,即一行只写一条语句
示例:如下例子不符合规范。
LogFilename now = null; LogFilename that = null;
应如下书写
LogFilename now = null;
LogFilename that = null;
5. *if, for, do, while, case, switch, default 等语句自占一行,且if, for, do, while等语句的执行语句无论多少都要加括号{}。
示例:如下例子不符合规范。
if(writeToFile) writeFileThread.interrupt();
应如下书写:
if(writeToFile)
{
writeFileThread.interrupt();
}
6. *相对独立的程序块之间、变量说明之后必须加空行。
示例:如下例子不符合规范。
if(log.getLevel() < LogConfig.getRecordLevel())
{
return;
}
LogWriter writer;
应如下书写
if(log.getLevel() < LogConfig.getRecordLevel())
{
return;
}
LogWriter writer;
int index;
7. *对齐只使用空格键,不使用TAB键。
说明:以免用不同的编辑器阅读程序时,因TAB键所设置的空格数目不同而造成程序布局不整齐。JBuilder、UltraEdit等编辑环境,支持行首TAB替换成空格,应将该选项打开。
8. *在两个以上的关键字、变量、常量进行对等操作时,它们之间的操作符之前、之后或者前后要加空格;进行非对等操作时,如果是关系密切的立即操作符(如.),后不应加空格。
说明:采用这种松散方式编写代码的目的是使代码更加清晰。
由于留空格所产生的清晰性是相对的,所以,在已经非常清晰的语句中没有必要再留空格,如果语句已足够清晰则括号内侧(即左括号后面和右括号前面)不需要加空格,多重括号间不必加空格,因为在Java语言中括号已经是最清晰的标志了。
在长语句中,如果需要加的空格非常多,那么应该保持整体清晰,而在局部不加空格。给操作符留空格时不要连续留两个以上空格。
示例:
(1) 逗号、分号只在后面加空格。
int a, b, c;
(2)比较操作符, 赋值操作符"="、 "+=",算术操作符"+"、"%",逻辑操作符"&&"、"&",位域操作符"<<"、"^"等双目操作符的前后加空格。
if (current_time >= MAX_TIME_VALUE)
a = b + c;
a *= 2;
a = b ^ 2;
(3)"!"、"~"、"++"、"--"、"&"(地址运算符)等单目操作符前后不加空格。
flag = !isEmpty; // 非操作"!"与内容之间
i++; // "++","--"与内容之间
(4)"."前后不加空格。
p.id = pid; // "."前后不加空格
(5) if、for、while、switch等与后面的括号间应加空格,使if等关键字更为突出、明显。
if (a >= b && c > d)
.2 建议
1. 类属性和类方法不要交叉放置,不同存取范围的属性或者方法也尽量不要交叉放置。
格式:
类定义
{
类的公有属性定义
类的保护属性定义
类的私有属性定义
类的公有方法定义
类的保护方法定义
类的私有方法定义
}
2 注释规范
A. 规则
1. 一般情况下,源程序有效注释量必须在30%以上。
说明:注释的原则是有助于对程序的阅读理解,在该加的地方都加了,注释不宜太多也不能太少,注释语言必须准确、易懂、简洁。可以用注释统计工具来统计。
2. 包的注释:包的注释写入一个名为 package.html 的HTML格式的说明文件放入当前路径。
说明:方便JavaDoc收集
示例:
com/huawei/iin/websmap/comm/package.html
3. 包的注释内容:简述本包的作用、详细描述本包的内容、产品模块名称和版本、公司版权。
说明:在详细描述中应该说明这个包的作用以及在整个项目中的位置。
格式:
<html>
<body>
<p>一句话简述。
<p>详细描述。
<p>产品模块名称和版本
<br>公司版权信息
</body>
</html>
示例:
<html>
<body>
<P>为 WEBSMAP 提供通信类,上层业务使用本包的通信类与 SMP-B 进行通信。
<p>详细描述。。。。。。。。
<p>IIN V100R001 WEBSMAP
<br>(C) 版权所有 2000-2001 华为技术有限公司
</body>
</html>
4. 文件注释:文件注释写入文件头部,包名之前的位置。
说明:注意以 /* 开始避免被 JavaDoc 收集
示例:
/*
* 注释内容
*/
package com.huawei.iin.websmap.comm;
5. 文件注释内容:版权说明、描述信息、生成日期、修改历史。
说明:文件名可选。
格式:
/*
* 文件名:[文件名]
* 版权:〈版权〉
* 描述:〈描述〉
* 修改人:〈修改人〉
* 修改时间:YYYY-MM-DD
* 跟踪单号:〈跟踪单号〉
* 修改单号:〈修改单号〉
* 修改内容:〈修改内容〉
*/
说明:每次修改后在文件头部写明修改信息,CheckIn的时候可以直接把蓝色字体信息粘贴到VSS的注释上。在代码受控之前可以免去。
示例:
/*
* 文件名:LogManager.java
* 版权:Copyright 2000-2001 Huawei Tech. Co. Ltd. All Rights Reserved.
* 描述: WIN V200R002 WEBSMAP 通用日志系统
* 修改人: 张三
* 修改时间:2001-02-16
* 修改内容:新增
* 修改人: 李四
* 修改时间:2001-02-26
* 跟踪单号:D20103
* 修改单号:WSS368
* 修改内容:。。。。。。
* 修改人: 王五
* 修改时间:2001-03-25
* 跟踪单号:D27153
* 修改单号:WSS498
* 修改内容:。。。。。。
*/
6. 类和接口的注释:该注释放在 package 关键字之后,class 或者 interface 关键字之前。
说明:方便JavaDoc收集
示例:
package com.huawei.iin.websmap.comm;
/**
* 注释内容
*/
public class CommManager
7. 类和接口的注释内容:类的注释主要是一句话功能简述、功能详细描述,
说明:可根据需要列出:版本号、生成日期、作者、内容、功能、与其它类的关系等。 如果一个类存在Bug,请如实说明这些Bug。
格式:
/**
* 〈一句话功能简述〉
* 〈功能详细描述〉
* @author [作者]
* @version [版本号, YYYY-MM-DD]
* @see [相关类/方法]
* @since [产品/模块版本]
* @deprecated
*/
说明:描述部分说明该类或者接口的功能、作用、使用方法和注意事项,每次修改后增加作者和更新版本号和日期,@since 表示从那个版本开始就有这个类或者接口,@deprecated 表示不建议使用该类或者接口。
示例:
/**
* LogManager 类集中控制对日志读写的操作。
* 全部为静态变量和静态方法,对外提供统一接口。分配对应日志类型的读写器,
* 读取或写入符合条件的日志纪录。
* @author 张三,李四,王五
* @version 1.2, 2001-03-25
* @see LogIteraotor
* @see BasicLog
* @since CommonLog1.0
*/
8. 类属性、公有和保护方法注释:写在类属性、公有和保护方法上面。
示例:
/**
* 注释内容
*/
private String logType;
/**
* 注释内容
*/
public void write()
9. 成员变量注释内容:成员变量的意义、目的、功能,可能被用到的地方。
10. 公有和保护方法注释内容:列出方法的一句话功能简述、功能详细描述、输入参数、输出参数、返回值、违例等。
格式:
/**
* 〈一句话功能简述〉
* 〈功能详细描述〉
* @param [参数1] [参数1说明]
* @param [参数2] [参数2说明]
* @return [返回类型说明]
* @exception/throws [违例类型] [违例说明]
* @see [类、类#方法、类#成员]
* @deprecated
*/
说明:@since 表示从那个版本开始就有这个方法;@exception或throws 列出可能仍出的异常;@deprecated 表示不建议使用该方法。
示例:
/**
* 根据日志类型和时间读取日志。
* 分配对应日志类型的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)
11. 对于方法内部用throw语句抛出的异常,必须在方法的注释中标明,对于所调用的其他方法所抛出的异常,选择主要的在注释中说明。 对于非RuntimeException,即throws子句声明会抛出的异常,必须在方法的注释中标明。
说明:异常注释用@exception或@throws表示,在JavaDoc中两者等价,但推荐用@exception标注Runtime异常,@throws标注非Runtime异常。异常的注释必须说明该异常的含义及什么条件下抛出该异常。
12. *注释应与其描述的代码相近,对代码的注释应放在其上方或右方(对单条语句的注释)相邻位置,不可放在下面,如放于上方则需与其上面的代码用空行隔开。
13. *注释与所描述内容进行同样的缩排。
说明:可使程序排版整齐,并方便注释的阅读与理解。
示例:如下例子,排版不整齐,阅读稍感不方便。
public void example( )
{
// 注释
CodeBlock One
// 注释
CodeBlock Two
}
应改为如下布局。
public void example( )
{
// 注释
CodeBlock One
// 注释
CodeBlock Two
}
14. *将注释与其上面的代码用空行隔开。
示例:如下例子,显得代码过于紧凑。
//注释
program code one
//注释
program code two
应如下书写:
//注释
program code one
//注释
program code two
15. *对变量的定义和分支语句(条件分支、循环语句等)必须编写注释。
说明:这些语句往往是程序实现某一特定功能的关键,对于维护人员来说,良好的注释帮助更好的理解程序,有时甚至优于看设计文档。
16. *对于switch语句下的case语句,如果因为特殊情况需要处理完一个case后进入下一个case处理,必须在该case语句处理完、下一个case语句前加上明确的注释。
说明:这样比较清楚程序编写者的意图,有效防止无故遗漏break语句。
17. *边写代码边注释,修改代码同时修改相应的注释,以保证注释与代码的一致性。不再有用的注释要删除。
18. *注释的内容要清楚、明了,含义准确,防止注释二义性。
说明:错误的注释不但无益反而有害。
19. *避免在注释中使用缩写,特别是不常用缩写。
说明:在使用缩写时或之前,应对缩写进行必要的说明。
B. 建议
1. *避免在一行代码或表达式的中间插入注释。
说明:除非必要,不应在代码或表达中间插入注释,否则容易使代码可理解性变差。
2. *通过对函数或过程、变量、结构等正确的命名以及合理地组织代码的结构,使代码成为自注释的。
说明:清晰准确的函数、变量等的命名,可增加代码可读性,并减少不必要的注释。
3. *在代码的功能、意图层次上进行注释,提供有用、额外的信息。
说明:注释的目的是解释代码的目的、功能和采用的方法,提供代码以外的信息,帮助读者理解代码,防止没必要的重复注释信息。
示例:如下注释意义不大。
// 如果 receiveFlag 为真
if (receiveFlag)
而如下的注释则给出了额外有用的信息。
// 如果从连结收到消息
if (receiveFlag)
4. *在程序块的结束行右方加注释标记,以表明某程序块的结束。
说明:当代码段较长,特别是多重嵌套时,这样做可以使代码更清晰,更便于阅读。
示例:参见如下例子。
if (...)
{
program code1
while (index < MAX_INDEX)
{
program code2
} // end of while (index < MAX_INDEX) // 指明该条while语句结束
} // end of if (...) // 指明是哪条if语句结束
5. *注释应考虑程序易读及外观排版的因素,使用的语言若是中、英兼有的,建议多使用中文,除非能用非常流利准确的英文表达。
说明:注释语言不统一,影响程序易读性和外观排版,出于对维护人员的考虑,建议使用中文。
6. 方法内的单行注释使用 //。
说明:调试程序的时候可以方便的使用 /* 。。。*/ 注释掉一长段程序。
7. 注释尽量使用中文注释和中文标点。方法和类描述的第一句话尽量使用简洁明了的话概括一下功能,然后加以句号。接下来的部分可以详细描述。
说明:JavaDoc工具收集简介的时候使用选取第一句话。
8. 顺序实现流程的说明使用1、2、3、4在每个实现步骤部分的代码前面进行注释。
示例:如下是对设置属性的流程注释
//1、 判断输入参数是否有效。
。。。。。
// 2、设置本地变量。
。。。。。。
9. 一些复杂的代码需要说明。
示例:这里主要是对闰年算法的说明。
//1. 如果能被4整除,是闰年;
//2. 如果能被100整除,不是闰年.;
//3. 如果能被400整除,是闰年.。
3 命名规范
A. 规则
1. 包名采用域后缀倒置的加上自定义的包名,采用小写字母。在部门内部应该规划好包名的范围,防止产生冲突。部门内部产品使用部门的名称加上模块名称。产品线的产品使用产品的名称加上模块的名称。
格式:
com.huawei.产品名.模块名称
com.huawei.部门名称. 项目名称
示例:
融合WEBSMAP包名 com.huawei.iin.websmap
通用消息转发包名 com.huawei.insa2.msgtrans
2. 类名和接口使用类意义完整的英文描述,每个英文单词的首字母使用大写、其余字母使用小写的大小写混合法。
示例:OrderInformation, CustomerList, LogManager, LogConfig, SmpTransaction
3. 方法名使用类意义完整的英文描述:第一个单词的字母使用小写、剩余单词首字母大写其余字母小写的大小写混合法。
示例:
private void calculateRate();
public void addNewOrder();
4. 方法中,存取属性的方法采用setter 和 getter方法,动作方法采用动词和动宾结构。
格式:
get + 非布尔属性名()
is + 布尔属性名()
set + 属性名()
动词()
动词 + 宾语()
示例:
public String getType();
public boolean isFinished();
public void setVisible(boolean);
public void show();
public void addKeyListener(Listener);
5. 属性名使用意义完整的英文描述:第一个单词的字母使用小写、剩余单词首字母大写其余字母小写的大小写混合法。属性名不能与方法名相同。
示例:
private customerName;
private orderNumber;
private smpSession;
6. 常量名使用全大写的英文描述,英文单词之间用下划线分隔开,并且使用 final static 修饰。
示例:
public final static int MAX_VALUE = 1000;
public final static String DEFAULT_START_DATE = "2001-12-08";
7. 属性名可以和公有方法参数相同,不能和局部变量相同,引用非静态成员变量(放在堆中,分配给对象的,对象的修改不会影响其他对象的该变量值)时使用 this (this指向当前对象)引用,引用静态成员变量(相当于全局变量,在类加载时就放入静态存储空间中;针对一个类,无论该类生成多少个对象,在全局中只有一个,任一个对象修改都会影响全局)时使用类名引用。
示例:
public class Person
{
private String name;
private static List properties;
public void setName (String name)
{
this.name = name;
}
public void setProperties (List properties)
{
Person.properties = properties;
}
B. 建议
1. 常用组件类的命名以组件名加上组件类型名结尾。
示例:
Application 类型的,命名以App 结尾——MainApp
Frame 类型的,命名以Frame 结尾——TopoFrame
Panel 类型的,建议命名以Panel 结尾——CreateCircuitPanel
Bean 类型的,建议命名以Bean 结尾——DataAccessBean
EJB 类型的,建议命名以EJB 结尾——DBProxyEJB
Applet 类型的,建议命名以Applet 结尾——PictureShowApplet
2. 如果函数名超过15 个字母,可采用以去掉元音字母的方法或者以行业内约定俗成的缩写方式缩写函数名。
示例:getCustomerInformation() 改为 getCustomerInfo()
3. 准确地确定成员函数的存取控制符号,不是必须使用 public 属性的,请使用 protected,不是必须使用 protected, 请使用 private。
示例: protected void setUserName(), private void calculateRate()
4. 含有集合意义的属性命名,尽量包含其复数的意义。
示例:customers, orderItems
4 编码规范
A. 规则
1. *明确方法功能,精确(而不是近似)地实现方法设计。一个函数仅完成一件功能,即使简单功能也应该编写方法实现。
说明:虽然为仅用一两行就可完成的功能去编方法好象没有必要,但用方法可使功能明确化,增加程序可读性,亦可方便维护、测试。
2. 应明确规定对接口方法参数的合法性检查应由方法的调用者负责还是由接口方法本身负责,缺省是由方法调用者负责。
说明:对于模块间接口方法的参数的合法性检查这一问题,往往有两个极端现象,即:要么是调用者和被调用者对参数均不作合法性检查,结果就遗漏了合法性检查这一必要的处理过程,造成问题隐患;要么就是调用者和被调用者均对参数进行合法性检查,这种情况虽不会造成问题,但产生了冗余代码,降低了效率。
3. 明确类的功能,精确(而不是近似)地实现类的设计。一个类仅实现一组相近的功能。
说明:划分类的时候,应该尽量把逻辑处理、数据和显示分离,实现类功能的单一性。
示例:
数据类不能包含数据处理的逻辑。
通信类不能包含显示处理的逻辑。
4. 所有的数据类必须重载toString() 方法,返回该类有意义的内容。
说明: 父类如果实现了比较合理的toString() ,子类可以继承不必再重写。
示例:
public TopoNode
{
private String nodeName;
public String toString()
{
return "NodeName : " + nodeName;
}
}
5. 数据库操作、IO操作等需要使用结束close()的对象必须在try -catch-finally 的finally中close()。
示例:
try
{
// ... ...
}
catch(IOException ioe)
{
//... ...
}
finally
{
try
{
out.close();
}
catch (IOException ioe)
//... ...
}
}
6. 异常捕获后,如果不对该异常进行处理,则应该纪录日志或者ex.printStackTrace() 。
说明:若有特殊原因必须用注释加以说明。
示例:
try
{
//.... ...
}
catch (IOException ioe)
{
ioe.printStackTrace ();
}
7. 自己抛出的异常必须要填写详细的描述信息。
说明:便于问题定位。
示例:
throw new IOException("Writing data error! Data: " + data.toString());
8. 运行期异常使用RuntimeException的子类来表示,不用在可能抛出异常的方法声明上加throws子句。非运行期异常是从Exception继承而来的,必须在方法声明上加throws子句。
说明:
非运行期异常是由外界运行环境决定异常抛出条件的异常,例如文件操作,可能受权限、磁盘空间大小的影响而失败,这种异常是程序本身无法避免的,需要调用者明确考虑该异常出现时该如何处理方法,因此非运行期异常必须有throws子句标出,不标出或者调用者不捕获该类型异常都会导致编译失败,从而防止程序员本身疏忽。
运行期异常是程序在运行过程中本身考虑不周导致的异常,例如传入错误的参数等。抛出运行期异常的目的是防止异常扩散,导致定位困难。因此在做异常体系设计时要根据错误的性质合理选择自定义异常的继承关系。
还有一种异常是Error 继承而来的,这种异常由虚拟机自己维护,表示发生了致命错误,程序无法继续运行例如内存不足。我们自己的程序不应该捕获这种异常,并且也不应该创建该种类型的异常。+
9. 在程序中使用异常处理还是使用错误返回码处理,根据是否有利于程序结构来确定,并且异常和错误码不应该混合使用,推荐使用异常。
说明:
一个系统或者模块应该统一规划异常类型和返回码的含义。
但是不能用异常来做一般流程处理的方式,不要过多地使用异常,异常的处理效率比条件分支低,而且异常的跳转流程难以预测。
10. *注意运算符的优先级,并用括号明确表达式的操作顺序,避免使用默认优先级。
说明:防止阅读程序时产生误解,防止因默认的优先级与设计思想不符而导致程序出错。
示例:
下列语句中的表达式
word = (high << | low (1)
if ((a | b) && (a & c)) (2)
if ((a | b) < (c & d)) (3)
如果书写为
high << 8 | low
a | b && a & c
a | b < c & d
(1)(2)虽然不会出错,但语句不易理解;(3)造成了判断条件出错。
11. *避免使用不易理解的数字,用有意义的标识来替代。涉及物理状态或者含有物理意义的常量,不应直接使用数字,必须用有意义的静态变量来代替。
示例:如下的程序可读性差。
if (state == 0)
{
state = 1;
... // program code
}
应改为如下形式:
private final static int TRUNK_IDLE = 0;
private final static int TRUNK_BUSY = 1;
private final static int TRUNK_UNKNOWN = -1;
if (state == TRUNK_IDLE)
{
state = TRUNK_BUSY;
... // program code
}
12. 数组声明的时候使用 int[] index ,而不要使用 int index[] 。
说明:使用int index[] 格式使程序的可读性较差
示例:
如下程序可读性差:
public int getIndex()[]
{
....
}
如下程序可读性好:
public int[] getIndex()
{
....
}
13. 调试代码的时候,不要使用 System.out 和 System.err 进行打印,应该使用一个包含统一开关的测试类进行统一打印。
说明:代码发布的时候可以统一关闭调试代码,定位问题的时候又可以打开开关。
14. 用调测开关来切换软件的DEBUG版和正式版,而不要同时存在正式版本和DEBUG版本的不同源文件,以减少维护的难度。
B. 建议
1. 记录异常不要保存exception.getMessage(),而要记录exception.toString()。
示例:NullPointException抛出时常常描述为空,这样往往看不出是出了什么错。
2. 一个方法不应抛出太多类型的异常。
说明: 如果程序中需要分类处理,则将异常根据分类组织成继承关系。如果确实有很多异常类型首先考虑用异常描述来区别,throws/exception子句标明的异常最好不要超过三个。
3. 异常捕获尽量不要直接 catch (Exception ex),应该把异常细分处理。
4. *如果多段代码重复做同一件事情,那么在方法的划分上可能存在问题。
说明:若此段代码各语句之间有实质性关联并且是完成同一件功能的,那么可考虑把此段代码构造成一个新的方法。
5. 对于创建的主要的类,最好置入main()函数,包含用于测试那个类的代码 。
说明:主要类包括:
1、能完成独立功能的类,如通讯。
2、具有完整界面的类,如一个对话框、一个窗口、一个帧等。
3、JavaBean 类。
示例:
public static void main(String[] arguments)
{
CreateCircuitDialog circuitDialog1 = new CreateCircuitDialog (null, "Ciruit", false);
circuitDialog1.setVisible(true);
}
6. 集合中的数据如果不使用了应该及时释放,尤其是可重复使用的集合。
说明:由于集合保存了对象的句柄,虚拟机的垃圾收集器就不会回收。
7. *源程序中关系较为紧密的代码应尽可能相邻。
说明:便于程序阅读和查找。
示例:矩形的长与宽关系较密切,放在一起。
rect.length = 10;
rect.width = 5;
8. *不要使用难懂的技巧性很高的语句,除非很有必要时。
说明:高技巧语句不等于高效率的程序,实际上程序的效率关键在于算法。
5 JTEST规范
A. 规则(1-2 级)
1. 在switch 中每个 case 语句都应该包含 break 或者 return 。
示例:
switch(weekOneDay)
{
case 1:
System.out.println("Monday");
break;
case 2:
System.out.println("Tuesday");
break;
case 3:
System.out.println("Wednesday");
break;
default:
System.out.println("Sorry I don't know");
}
我的本意只输出“Monday”但是如果去掉第一个Break,输出的结果为:
Monday
Tuesday
2. 不要使用空的for 、if 、while 语句。
3. 在运算中不要减小数据的精度。
下面是不正确示例:
double d1 = 1.0000002d;
double d2 = 0.0000002;
System.out.println(d1-d2);
打印结果为0.9999999999999999
4. switch 语句中的 case 关键字要和后面的常量保持一个空格,switch 语句中不要定义case 之外的无用标签。
5. 不要在if 语句中使用等号= 进行赋值操作。
说明:使用if(a=b)编译不能通过,但是if (a = = (b = e xpress))是可以编译通过的,但是不推荐使用
示例:
if (a = = (b = e xpress)) //其中等号“= =”与赋值“=”操作符容易混淆
{
//语句
6. 静态成员或者方法使用类名访问,不使用句柄访问。
说明:不要使用创建的实例(或this、super)访问,而直接使用类名访问这样读者一看到就知道这个方法或属性是静态的(因为类只能直接访问静态的属性或方法,不能直接访问非静态属性或方法)。
7. 方法重载的时候,一定要注意方法名相同,避免类中使用两个非常相似的方法名。
说明:方法重载的时候如果方法名不相同即它们不存在重载关系,一个类中存在几个非常相似方法名这样使得程序可读性差。
重载只关注方法名、参数类型、个数相同,不关注返回类型。
8. 不要在ComponentListener.componentResized() 方法中调用 setResize() 方法。
说明:ComponentListener为一个接口,该接口是用来监听"组件"的尺寸变化事件,当"组件"的尺寸发生更改,setResize()方法就会调用该接口的componentResized方法,如果在componentResized方法中调用setResize()方法会造成死循环
9. 不要覆盖父类的静态方法和私有方法。
说明:静态方法和私有方法不能被继承,子类实现不了覆盖,只能属于重写该方法。
覆盖父类的静态方法和私有方法实现不了多态,下面是覆盖静态方法的示例:
class Father
{
public static void print()
{
System.out.println("father静态方法");
}
}
public class Son extends Father
{
public static void print()
{
System.out.println("other静态方法");
}
public static void main(String[] args)
{
Father intance = new Son()
intance.print();
}
打印的结果为“father静态方法”。在类外部访问不了私有方法,所以实现不了覆盖多态。
10. 不要覆盖父类的属性。
说明:属性不对外提供访问(不会提供public权限),只私有属性不能被继承,属性的重写无意义
11. 不要使用两级以上的内部类。
说明:嵌套太多,1容易出错,2不容易理解
12. 去掉接口中多余的定义(不使用 public, abstract, static, final 等,这是接口中默认的)。
说明:接口是抽象方法和常量的定义的集合。
示例:
public interface Runner //public是一定要写,否则限制了访问权限
{
int id = 1; //默认是public static final int id=1;
void run (); //默认是public void run();
}
其中id是常量,run是抽象方法。
13. 不要定义不会被用到的局部变量、类私有属性、类私有方法和方法参数。
14. 显式初始化所有的静态属性。
一般使用静态属性之前不会对静态属性赋值,而是直接用类访问静态属性,
如果你没初始化他的默认值为0;
static(定义的属性在内存中只有一份拷贝)在类载入的时候就会被初始化,可以被修改。如果没有显示初始化,系统会给个默认值
15. 不要使用 System.getenv() 方法。
建议不要使用'System.getenv ()
不建议使用'System.getenv ()',这个方法看起来很好用,不过并不是所有的系统都有环境变量的。
不用这个方法也可能带来一些不方便。错误示例:
void method (String name) {
System.getenv (name); // 可以用其他方法来代替
}
如果不用这个方法,我们可以用其它的方法来代替。比如:'System.getProperty ()’,'getTypeName ()'等,
这也可以找到java的系统属性。
16. 不要硬编码 ‘\n’和‘\r’作为换行符号。
不要使用’\n’或者'\r'来分行
这两个标记看来很普遍,特别是’\n’。我们经常用来作为分行用。但是不同的系统用不同的分行字符,
所以这些字符在某些意义上违背了java的平台无关性。
错误示例:
System.out.println("Hello\n" + name);
我们可以用其它的一些方法来代替,比如println(),这个方法在不同的系统平台上都起到相同的作用。
后者推荐大家用这个方法:System.getProperty("line.separator")
17. 不要直接使用 java.awt.peer.* 里面的接口。
该包在现有的1.4.2的JDK中无法查到
18. 使用 System.arraycopy() ,不使用循环来复制数组。
19. 避免不必要的 instanceof 比较运算和类造型运算。
20. 不要在 finalize() 方法中删除监听器(Listeners)。
不要在finalize()方法中删除Listeners,finalize()只有再没有对象引用的时候调用,如果Listeners从finalize()方法中去除了,被finalize的对象将不会再垃圾收集中去除。
Public void finalize() throws Throwable{
BButton removeActionListener(act);
}
21. 在 finalize() 方法中一定要调用 super.finalize() 方法
如果没有调用super.finalize()只执行本类中的finalize(),即不会执行Object中的finalize();
这里的finalize ()是java在进行垃圾收集的时候调用的,和finally不一样。如果你的父类没有定义finally()的话,你也应该调用。
这里有两个原因:
1)在不改变代码的情况下能够将父类的finally方法加到你的类中。
2)以后你会养成习惯调用父类的finally方法,即使父类没有定义finally方法的时候。
正确的方法应该如此:
public class parentFinalize {
protected void finalize () throws Throwable {
super.finalize(); // FIXED
}
22. 在 finalize() 方法中的 finally 中调用 super.finalize() 方法。
为了确保在程序不管有没有出现异常的情况下都能执行super.finalize()
finally 再异常处理时提供 finally 块来执行任何清除操作。如果抛出一个异常,那么相匹配的 catch 子句就会执行,然后控制就会进入 finally 块(如果有的话)。finalize 方法名。Java 技术允许使用 finalize() 方法在垃圾收集器将对象从内存中清除出去之前做必要的清理工作。这个方法是由垃圾收集器在确定这个对象没有被引用时对这个对象调用的。它是在 Object 类中定义的, 因此所有的类都继承了它。子类覆盖 finalize() 方法以整理系统资源或者执行其他清理工作。finalize() 方法是在垃圾收集器删除对象之前对这个对象调用的。
23. 进行字符转换的时候应该尽可能的较少临时变量。
24. 使用ObjectStream 的方法后,调用reset() ,释放对象。
25. 线程同步中,在循环里面使用条件测试(使用 while(isWait) wait() 代替 if(isWait) wait())。
26. 不掉用 Thread 类的 resume(), suspend(), stop() 方法。
说明:会导致死锁发生。
虽然stop可以避免死锁发生。在程序运行的过程中如果停止可能会导致数据的不一致性。
27. 减小单个方法的复杂度,使用的 if, while, for, switch 语句要在10个以内。
28. 在Servlets中,重用JDBC连接的数据源。
节省系统资源
29. 减少在Sevlets中使用的同步方法。
说明:Sevlets本身是已多线程的方式响应多个用户的请求。如果多个用户都要调用同一个同步方法,这个时候只能响应一个用户。
30. 不定义在包中没有被用到的友好属性、方法和类。
友好属性的访问控制权限是在一个包中,在一个包中如果不用那定义他是多余的。
31. 没有子类的友好类应该定义成 final 。
32. 没有被覆盖的友好方法应该定义成 final 。
如果一个类被声明为final,意味着它不能再派生出新的子类,不能作为父类被继承。
因此一个类不能既被声明为 abstract的,又被声明为final的。将变量或方法声明为final,可以保证它们在使用中不被改变。被声明为final的变量必须在声明时给定初值,而在以后的引用中只能读取,不可修改。被声明为final的方法也同样只能使用,不能重载
B. 建议(3级或以上)
1. 为 switch 语句提供一个 default 选项。
请参看:规则1,在没有符合case 条选项件的情况下default 选项给用户提供友好的信息。
2. 不要在 for 循环体中对计数器的赋值。
3. 不要给非公有类定义 public 构建器。
说明:定义成非公有类访问控制权限,这样难以控制程序-,还有在同一个文件中定义了多个公有类编译会失败。
4. 不要对浮点数进行比较运算,尤其是不要进行 ==, !=运算,减少 >, < 运算。
两个不等的浮点数进行“==”比较有可能比较的结果是相等的。
5. 实现 equals() 方法时,先用 getClass() 或者 instanceof 进行类型比较,通过后才能继续比较。
首先两个对象先用getClass()获取它们所属的类,再用instanceof看这两个对象是不属于同一个类,如果不是,就不用equals()比较了。
6. 不要重载 main() 方法用作除入口以外的其他用途。
7. 方法的参数名不要和类中的方法名相同。
编译不会出错,这样会程序可读性更差
8. 除了构建器外,不要使用和类名相同的方法名。
会使读者把那个不是构造器的函数与构造函数混淆。编译不会出错
9. 不要定义 Error 和 RuntimeException 的子类,可以定义 Exception 的子类。
error 表示恢复不是不可能但很困难的情况下的一种严重问题。比如说内存溢出。不可能指望程序能处理这样的情况。
exception 表示一种设计或实现问题。也就是说,它表示如果程序运行正常,从不会发生的情况。
Huxiaoyong 细化
10. 线程中需要实现 run() 方法。
说明:创建线程有两种方法,继承Thread类和实现Runnable接口。
后者无疑是要实现的,前者如果你不覆盖Thread中的run()方法什么事都不干,这样创建的线程是无意义的。
11. 使用 equals() 比较两个类的值是否相同。
“==”操作符用于比较两个变量(包括基本类型与引用类型变量)的值是否相同,equals()方法用于比较两个对象(注意:这里只能是引用类型变量)的内容是否相同。
java虚拟机用创建对象的内存地址(内存区)付给前面声明的变量。
例如 String s = new String("hello");这个语句是把对象new String("hello")的内存地址付给s,即现在变量s指向系统为对象new String("hello")分配的内存地址(内存区);
其实变量s真正的值为对象new String("hello")的内存地址(内存区);
在java中也有指针,只是java让指针对程序员不可见,即程序员不可以控制指针。
示例:
public class comp
{
public comp()
{
}
public void weatherEquals()
{
String s1 = "hello";
String s2 = "hello";
//操作符“=”右边的步骤:先创建一个内容为“hello”的对象,再返回这个对象的内 //存地址给s3;所以s3的值为这个对象内存地址
String s3 = new String("hello");
String s4 = new String("hello");
if (s1==s2)
{
//这里相等,是因为编译器会做优化工作, 发现S2的内容根S1一样,编译器就将 //s2的"指针"指向s1指向的内存
System.out.println("s1与s2是指向同一个对象的内存区");
}
else
{
System.out.println("s1与s2不是指向同一个对象的内存区");
}
if(s1.equals(s2))
{
System.out.println("s1与s2所指向对象的内容相同");//对象的内容是指对象的某个或某些属性值
}
else
{
System.out.println("s1与s2所指向对象的内容不相同");
}
if(s3==s4)
{
System.out.println("s3与s4是指向同一个对象的内存区");
}
else
{
//这里不是指向同一个对象,是因为你手工指定jvm用new去分配两块内存, 所以需 //要从内存块的角度来理解
System.out.println("s3与s4不是指向同一个对象的内存区");
}
if(s3.equals(s4))
{
System.out.println("s3与s4所指向对象的内容相同");
}
else
{
System.out.println("s3与s4所指向对象的内容不相同");
}
}
public static void main(String[] args)
{
comp comp1 = new comp();
/*下面执行结果为:
s1与s2是指向同一个对象的内存区
s1与s2所指向对象的内容相同
s3与s4不是指向同一个对象的内存区
s3与s4所指向对象的内容相同
*/
comp1.weatherEquals();
}
}
12. 字符串和数字运算结果相连接的时候,应该把数字运算部分用小括号括起来。
说明:如果你没用括号括起来,先会把数字转换为字符串再与已有的字符串相连,
例如:
int iNumber1 = 2;
int iNumber2 = 3;
String sString1 = "nhao" + iNumber1 + iNumber2;
String sString2 = "nhao" + (iNumber1 + iNumber2);
System.out.println(sString1);
System.out.println(sString2);
前一个打印语句的结果为“nihao23”,后一个为"nihao5";
13. 类中不要使用非私有(公有、保护和友好)的非静态属性。
14. 在类中对于没有实现的接口,应该定义成抽象方法,类应该定义成抽象类。(5级)
说明:因为继承接口要实现其中的所有抽象方法。继承抽象类可以不用实现其中所有抽象方法。
15. 不要显式导入 java.lang.* 包;
java会默认的导入java.lang包中的所有类。所以你没有必要再导入这个包。
16. 初始化时不要使用类的非静态属性。
说明:你用一个非静态属性去初始化一个变量,有可能非静态属性自己本身还没有初始化。
17. 显式初始化所有的局部变量。
因为没有初始化的字段会是一个潜在的bug,如一个整数开始你不能确定什么值就初始化一个0给它。
所以最好初始化类里面的所有的字段。特别是静态的字段,最好在一开始就分配一个初始值
错误示例:
public class CSI {
public CSI () {
this (12);
k = 0;
}
public CSI (int val) {
j = val;
}
private int i = 5;
private int j;
private int k;
}
正确示例:
public class CSIFixed {
public CSIFixed () {
this (12);
}
public CSIFixed (int val) {
j = val;
k = 0;
}
private int i = 5;
private int j;
private int k;
}
18. 按照方法名把方法排序放置,同名合同类型的方法应该放在一起。
19. 不要使用嵌套赋值,即在一个表达式中使用多个 = 。
20. 不要在抽象类的构建器中调用抽象方法。
21. 重载 equals() 方法的同时,也应该重载 hashCode() 方法。
每一个存在内存中的实例的hashcode()返回码是不同的,通常可能需要在equals()方法中判断两个引用指向的是不是同一个对象,这是就需要比较hashcode了
Huxiaoyong 细化
22. 工具类(Utility)不要定义构建器,包括私有构建器。
这是一种软件设计思想,工具类通常都是设计成单例类,没有必要允许用户创建多个实例
23. 不要在 switch 中使用10个以上的 case 语句。
24. 把 main() 方法放在类的最后。
25. 声明方法违例的时候不要使用 Exception ,应该使用它的子类。
Exeption报的异常没有它的子类具体。例如,DataFormatException,如果出异常就知道是数据格式异常。 IOException,就知道是IO操作的异常。
26. 不要直接扔出一个Error ,应该扔出它的子类。
error 表示恢复不是不可能但很困难的情况下的一种严重问题。比如说内存溢出。不可能指望程序能处理这样的情况。
exception 表示一种设计或实现问题。也就是说,它表示如果程序运行正常,从不会发生的情况。 子类更具体
27. 在进行比较的时候,总是把常量放在同一边(都放在左边或者都放在右边)。
28. 在可能的情况下,总是为类定义一个缺省的构建器。
说明:没有定义一个缺省的构建器,但定义了有一个参数的构造器,这个缺省的构建器就不存在了。那么它的子类的构造器没有指定调用它的某个构造器程序就会编译失败。
29. 在捕获违例的时候,不使用 Exception, RuntimeException, Throwable,尽可能使用它们的子类。
说明:它们的子类报的异常更具体,即让你更清楚知道是什么异常。
30. 在接口或者工具类中中定义常量。(5级)
31. 使用大写‘L’表示 long 常量。(5级)
说明:长整常量的时候,用L来代替l.
因为l很容易和数字1混一起。
错误示例:
long temp = 23434l;
正确示例:
long temp = 23434L;
32. main() 方法必须是 public static void main(String[]arg)。(5级)
说明:由于Java虚拟机需要调用类的main()方法,所以该方法的访问权限必须是public,又因为Java虚拟机在执行main()方法时不必创建对象,所以该方法必须是static的。该方法接收一个String类型的数组参数,该数组中保存执行Java命令时传递给所运行的类参数。
33. 对返回类型为 boolean 的方法使用 is 开头,其它类型的不能使用。
34. 对非boolean类型取值方法(getter)使用 get 开头,其它类型的不能使用。
35. 对于设置值的方法(setter)使用 set 开头,其它类型的不能使用。
36. 方法需要有同样数量参数的注释 @param。
37. 不要在注释中使用不支持的标记,如:@unsupported 。
38. 不要使用 Runtime.exec() 方法。
在本程序进程的过程中启动另一个进程。
例如:
try
{
java.lang.Runtime.getRuntime().exec("mspaint");
}catch (Exception e)
{
}
启动微软的画图软件。
39. 不要自定义本地方法(native method)。
java代码调用其他语言的代码,例如System中
public static native void arraycopy(Object src, int srcPos, Object dest, int destPos,int length);
Huxiaoyong 细化
40. 使用尽量简洁的运算符号。
41. 使用集合时设置初始容量。
说明:集合类是无边界的。 在创建集合对象时java会默认分配一段空间给它,默认的空间可能过大,这样就浪费空间。在程序运行过程中可能默认的空间不够java又要重新创建一个集合对象这样浪费时间,
42. 单个首字符的比较使用 charAt() 而不用 startsWith() 。
43. 对于被除数或者被乘数为2的n次方的乘除运算使用移位运算符 >>, << 。
44. 一个字符的连接使用‘ ’而不使用 “ ”,如:String a = b + 'c'。
''字符是基本的数据类型,""是引用数据类型,基本数据运算的效率更高。
45. 不要在循环体内调用同步方法和使用 try-catch 块。
While(i<10)
{
Try
{
}
Catch(Exception e)
{
}
}
上述代码的问题就是当有异常抛出时不是结束循环体,而是让循环体继续循环.
46. 不要使用不必要的布尔值比较,如:if (a.equals(b)), 而不是 if (a.equals(b)==true)。
47. 常量字符串使用 String, 非常量字符串使用 StringBuffer 。
String 的内容是不可变,StringBuffer的内容是可变;
示例:
48. 在循环条件判断的时候不要使用复杂的表达式。
49. 对于“if (condition) do1; else do2;”语句使用条件操作符“if (condition)?do1:do2;”。
50. 不要在循环体内定义变量。
for循环体中是用堆栈对定义的变量分配空间,即每次循环定义的变量占用的内存空间不同,在定义变量的时候又要发费时间,这样既浪费空间又浪费时间。
51. 使用StringBuffer的时候设置初始容量。
在创建StringBuffer对象时java会默认分配一段空间给它,默认的空间可能过大,这样就浪费空间。在程序运行过程中可能默认的空间不够java又要重新创建一个StringBuffer这样浪费时间,
52. 尽可能的使用局部变量进行运算。
变量的作用域过大这是一个隐患的Bug,可能你在运行这段程序的时候而被另一段改变这个变量值而导致程序错误运行。
53. 尽可能少的使用 ‘!’操作符。(5级)
54. 尽可能的对接口进行 instanceof 运算。(5级)
55. 不要使用 Date[] 而要使用 long[] 替代。
基本类型数据运算效率更高
56. 不要显式调用 finalize() 。
虽然显式的调用这个方法可以使你确保你的调用,但是当这个方法收集了以后垃圾收集会再收集一次。需要确保这个方法只执行一次
57. 不要使用静态集合,其内存占用增长没有边界。
58. 不要重复调用一个方法获取对象,使用局部变量重用对象。
说明:运行方法效率低,直接用变量引用对象效率更高。
下面是错误的示例:
Runtime.getRuntime().exec("mspaint");
Runtime.getRuntime().exec("notepad");
.............
下面是正确的示例:
Runtime run = Runtime.getRuntime();
run. exec("mspaint");
run. Exec("notepad");
................
59. 线程同步中,使用 notifyAll() 代替 notify()。
60. 避免在同步方法中调用另一个同步方法造成的死锁。
示例:
class A
{
synchronized void foo(B b)
{
try
{
Thread.sleep(1000);
}
catch(Exception e)
{
System.out.println(e.getMessage());
}
b.last();
}
synchronized void last()
{
System.out.println("inside a.last");
}
}
class B
{
synchronized void bar(A a)
{
try
{
Thread.sleep(1000);
}
catch(Exception e)
{
System.out.println(e.getMessage());
}
a.last();
}
synchronized void last()
{
System.out.println("inside b.last");
}
}
public class Deadlock implements Runnable
{
A a = new A();
B b = new B();
Deadlock()
{
new Thread(this).start();
a.foo(b);
}
public void run()
{
b.bar(a);
}
public static void main(String args[])
{
new Deadlock();
System.out.println("end");
}
}
在上述程序用sleep来强制foo和bar这两个同步方法出现死锁;
在类A中同步方法foo调用B类同步方法last,在类B中同步方法bar调用A类同步方法laster而出现死锁
61. 非同步方法中不能调用 wait() , notify() 方法。
62. 使用 wait(), notify() 代替 while(), sleep() 。
sleep()方法是使线程停止一段时间的方法。在sleep 时间间隔期满后,线程不一定立即恢复执行。这是因为在那个时刻,其它线程可能正在运行而且没有被调度为放弃执行,除非(a)“醒来”的线程具有更高的优先级(b)正在运行的线程因为其它原因而阻塞。wait()是线程交互时,如果线程对一个同步对象x 发出一个wait()调用,该线程会暂停执行,被调对象进入等待状态,直到被唤醒或等待时间到。
63. 不要使用同步方法,使用同步块。(5级)
64. 把所有的公有方法定义为同步方法。 (5级)
65. 实现的 Runnable.run() 方法必须是同步方法。 (5级)
66. 一个只有abstract方法、final static 属性的类应该定义成接口。
67. 在 clone() 方法中应该而且必须使用 super.clone() 而不是 new 。
new只是显示的初始一个对象(对象内部数据都为初始值),而clone()是创建一个和现有对象实例完全相同的对象,(clone对象中数据和当当前对象数据完全相同)
68. 常量必须定义为 final 。
69. 在 for 循环中提供终止条件。
70. 在 for, while 循环中使用增量计数。
71. 使用 StringTokenizer 代替 indexOf() 和 substring() 。
72. 不要在构建器中使用非 final 方法。
73. 不要对参数进行赋值操作。(5级)
74. 不要通过名字比较两个对象的类,应该使用 getClass() 。
75. 安全:尽量不要使用内部类。
使所有的内部类"private".Java允许一个类包含另外一个类,但是Java byte code没有这个概念。类被编译器解释成package-private类。内部类能访问外部类的属性,如果内部类能被随意访问, 外部类的属性也能被随意访问。
错误示例:
public class INNER {
class INNER_Class {
void setValue(int i) {
_value = i; // 现在包就可以访问了
}
}
private int _value;
}
所以需要加上private class INNER_Class
76. 安全:尽量不要使类可以克隆。
77. 安全:尽量不要使接口可以序列化。
如果一个字节数组包含了一个被序列化的对象。攻击者就能读到这个对象的内部状态合字段(包括private的)。
错误示例:
public interface sample extends java.io.Serializable
78. 安全:尽量不要使用友好方法、属性和类。
79. Servlet:不要使用 java.beans.Beans.instantiate() 方法。
80. Servlet:不再使用HttpSession时,应该尽早使用 invalidate() 方法释放 。
81. Servlet:不再使用JDBC资源时,应该尽早使用 close() 方法释放 。
82. Servlet:不要使用Servlet的 SingleThreadModel,会消耗大量资源。
83. 国际化:不要使用一个字符进行逻辑操作,使用 Characater。
一个单个字符的前后不要用逻辑操作符,如果代码要在一个国家环境中运行的话。我们可以使用字符比较方法,
这些方法使用统一字符比较标准来定义字符的属性的。
错误示例:public class CLO {
public boolean isLetter (char ch) {
boolean _isLetter = ( ch >= 'a' && ch <= 'z') //错误
|| (ch >= 'A' && ch <= 'Z');
return _isLetter;
}
}
正确示例:
public class CLOFixed {
public boolean isLetter (char ch) {
boolean _isLetter = Character.isLetter(ch);
return _isLetter;
}
}
84. 国际化:不要进行字符串连接操作,使用MessageFormat 。
85. 国际化:不要使用 Date.toString() ,Time.toString() 方法。
不要使用'Date.toString ()'方法,日期格式对于地区和语言不同的国家来说是不一样的,务必不要使用。'DateFormat'类提供了一个预定义的格式类型来指定本地的格式。
错误示例:
public void printToday () {
Date today = new Date ();
String todayStr = today.toString ();
System.out.println (todayStr);
}
正确示例:
public void printToday () {
Locale currentLocale = Locale.getDefault ();
DateFormat dateFormatter = DateFormat.getDateInstance (
DateFormat.DEFAULT, currentLocale);
Date today = new Date ();
String todayStr = dateFormatter.format (today);
System.out.println (todayStr);
}
因为时间的格式各个国家也不一样。如果你使用日期格式类,你的应用就能够在世界上各个地方正确的显示时间和日期了。首先,用'getTimeInstance ()'方法创建一个formatter。然后,调用'format ()'方法。
错误示例:
public class TTS {
public void printTime (Time t1) {
String timeStr = t1.toString ();
System.out.println (timeStr);
}
}
正确示例:
import java.sql.Time;
import java.text.DateFormat;
import java.util.Locale;
public class TTSFixed {
public void printTime (Time t1) {
DateFormat timeFormatter = DateFormat.getTimeInstance(
DateFormat.DEFAULT, Locale.getDefault ());
String timeStr = timeFormatter.format(t1);
System.out.println (timeStr);
}
}
86. 国际化:字符和字符串常量应该放在资源文件中。
87. 国际化:不要使用数字的 toString() 方法。
在全球化的开发中,不要对数字变量使用'toString ()'方法,这个对于java.lang.Number的任何子类都适用。
包括:BigDecimal, BigInteger, Byte, Double, Float, Integer, Long, and Short.
对于这样的情况,java里也定义了"NumberFormat"方法来格式化。
错误示例:
public class NTS {
public void method (Double amount) {
String amountStr = amount.toString ();
System.out.println (amountStr);
}
}
正确示例:
public class NTSFixed {
public void method (Double amount) {
Locale currentLocale = Locale.getDefault ();
NumberFormat numberFormatter =
NumberFormat.getNumberInstance (currentLocale);
String amountStr = numberFormatter.format (amount); //
System.out.println (amountStr + ' ' + currentLocale.toString ());
}
}
88. 国际化:不要使用 StringBuffer , StringTokenizer类。
89. 国际化:不要使用 String 类的 compareTo(), equals() 方法。
建议不要使用'String.equals ()'方法,因为在统一字符比较标准中不一定按照相关的顺序来比较。 'Collator'提供的预定义整理规则来排序string,Collator类调用'getInstance ()'方法,一般来说,可以为默认的本地创建一个Collator。例如:Collator myCollator = Collator.getInstance (); 创建Collator的时候你也可以指定一个特殊的locale。 例如:Collator myFrenchCollator = Collator.getInstance (Locale.FRENCH); 然后就可以调用'Collator.compare ()'来执行一个本地的字符比较myCollator.compare (s1,s2);
错误示例:
public class SE {
public boolean compstr (String s1, String s2) {
boolean b = (s1.equals (s2));
return b;
}
}
正确示例:
public class SEFixed {
public boolean compstr (String s1, String s2) {
Collator myCollator = Collator.getInstance ();
boolean b = (myCollator.compare(s1,s2) == 0);
return b;
}
}
90. 复杂度:建议的最大规模:
继承层次 5层
类的行数 1000行(包含{})
类的属性 10个
类的方法 20个
类友好方法 10个
类私有方法 15个
类保护方法 10个
类公有方法 10个
类调用方法 20个
方法参数 5个
return语句 1个
方法行数 30行
方法代码 20行
注释比率 30%~50%
相关推荐
企业知识库管理系统是一款基于Java语言开发的软件应用,主要用于企业内部知识的收集、存储、管理和分享。这个系统的核心目标是提升企业的知识管理效率,促进团队协作,提高员工的专业能力,从而推动企业的持续发展。...
Java开发语言是全球范围内广泛应用的编程语言,尤其在企业级应用和服务器端开发中占据主导地位。本资料"java开发知识库管理系统.zip"提供了一个完整的源码参考,旨在帮助开发者深入理解Java在构建知识库管理系统中的...
11. **Java EE**:如果深入到企业级开发,Java EE(Java Enterprise Edition)的知识也非常重要,包括Servlet、JSP、EJB、JMS、JPA等技术。 12. **框架应用**:Spring、MyBatis、Hibernate等框架是现代Java开发的...
Java有丰富的类库支持,适用于开发桌面应用、Web应用、移动应用以及企业级应用。 二、Java语法基础: 1. 数据类型:Java分为基本数据类型(如int、char、float、boolean等)和引用数据类型(如类、接口、数组)。 2...
Java是目前企业开发中最常用的编程语言之一,Java面试知识点涵盖了Java语言的方方面面,包括Java基础知识、Java高级知识、Java设计模式、Java框架等等。以下是Java核心面试知识点的整理。 一、JVM JVM(Java ...
### Java基础知识精炼 #### 一、Java概述与发展历程 Java是一种高级编程语言,由Sun Microsystems公司的James Gosling等人于1991年开始研发,原名为Oak,旨在控制嵌入式设备如有线电视交换盒和PDA。1994年正式更名...
Spring是Java企业级应用中的核心框架,它提供了依赖注入(DI)和面向切面编程(AOP)的功能。Spring MVC是Spring的一部分,用于构建Web应用程序。通过配置XML或使用Java配置,开发者可以轻松管理对象之间的依赖关系...
Java是一种广泛使用的面向...总之,Java核心知识是开发者必须掌握的基础,无论是在桌面应用、企业级Web应用还是移动开发领域,都有广泛的应用。通过深入理解和实践这些知识点,开发者能够编写出高效、稳定的Java程序。
在“java基础知识应用”这个主题中,我们主要探讨的是Java语言的基础概念及其在实际开发中的应用,特别是与数据库交互的部分。 一、Java语言基础 1. 类与对象:Java基于面向对象的编程理念,所有程序都是由类和对象...
标题中提到的“java核心知识.pdf”,意味着接下来的内容会围绕Java编程语言的核心知识点展开。Java是一种广泛使用的面向对象的编程语言,具有跨平台、面向对象、分布式、健壮、安全性等特点。它广泛应用于企业级应用...
Spring是Java企业级应用的事实标准,提供依赖注入(DI)、面向切面编程(AOP)、事务管理等功能。Spring Boot简化了配置,Spring Cloud则为微服务提供了全面支持。熟悉Spring的核心模块和扩展工具,能提高开发效率。...
JavaSE 是桌面应用程序的开发基础,JavaEE 是企业环境下的应用程序开发,而 JavaME 是用于电子消费产品和嵌入式设备的开发。 Java 的开发和运行环境是 JDK(Java Development Kit),包括 Java 语言的开发工具和 ...
在Java企业级开发中,核心知识点主要包括以下几个方面: 1. **Java基础**:首先,理解并熟练掌握Java编程语言的基本语法是至关重要的,包括类、对象、继承、多态等面向对象特性,以及异常处理、集合框架、IO流、...
Java知识体系总结 Java是一种广泛使用的面向对象的编程语言,由Sun Microsystems(现已被Oracle公司收购)于1995年推出。它以其“一次编写,到处运行”的特性闻名,适用于开发跨平台的应用程序,包括桌面应用、企业...
JAVA是目前最流行的编程语言之一,广泛应用于Web开发、 Android应用开发、企业软件开发等领域。作为一名开发者,掌握JAVA核心知识点是非常重要的。本文档将对JAVA核心知识点进行详细的总结和剖析。 目录 JAVA...
Java分为三大技术架构:JAVAEE(Java Platform Enterprise Edition)主要用于开发企业级Web应用,JAVASE(Java Platform Standard Edition)则支持桌面应用的开发,是其他两个架构的基础,而JAVAME(Java Platform ...
JAVA模块知识小结涵盖的内容非常广泛,包含了Java技术栈中的多个重要知识点,从基础的开发工具到框架、数据库以及编程语言本身,以下是对给定文件中提到的各项技术的详细知识点梳理: 1. Hibernate和Ibatis ...
【Java基础知识概述】 Java是一种广泛使用的高级编程语言,由Sun Microsystems公司(现已被Oracle公司收购)于1991年发起的“绿色项目”孕育而生,最初名为Oak。尽管最初的项目目标并未实现,但Java作为一种面向...
### Java基础知识总结 #### 一、Java概述 Java是由Sun Microsystems公司(现已被Oracle收购)在1991年由James Gosling(詹姆斯·高斯林)领导的一个团队开始开发的一种面向对象的编程语言。最初被命名为Oak,目标...