Java的中文编程与配置心得

时间:2024.5.2

Java的中文编程与配置心得

Java的中文问题历史悠久,连绵不绝,至今也没有完全解决,但是上有政策下有对策,我们总是有办法搞定它的。跟Java相关的中文问题主要有两类,一类是编程的问题,涉及到I/O,内码转换等。第二类是Java运行环境的配置,涉及字体,属性配置等。我刚刚用了一天的时间解决这些问题,觉得很有必要给自己写个备忘录之类的。

我看还是从问题入手吧,这样不致于让大家打瞌睡。我想写个程序,这个程序有个基本功能就是显示文件内容,我用JTextArea来做显示的事情,程序简单的到家了,但是就是中文都是乱码。我的配置是JBuilder7,JBuilder自带的JDK1.3.3_b24,我自己装的JDK是JDK1.4.0_02_b02,都是主流的JDK.操作系统是英文Windows2000加中文支持包。

我尝试换JDK,1.3.3和1.4.0都不行,down一个最新的j2sdk-1_4_1-rc也是不行,好像不是JDK的问题,于是我就把精力集中到I/O的编码转换上,我查阅了网上若干关于JAVA中文问题的文章,把编码转换搞的倍儿清楚,可是怎么试,换什么编码折腾都不行,反而显示的更糟糕,当初还是乱的有些规矩,就是象在纯英文系统上显示的那样,好歹我还知道那是汉字,只是显示不出来,等我折腾编码,就变得都是问号了。唉,郁闷!

编码转换心得:

JAVA内部是UNICODE编码,在I/O时如果使用Reader/Writer就要发生编码转换,使用系统属性file.encoding作为编码方式。如果使用Stream就没有转换的事情了,那是Binary的数据。

有用的方法有:

1.在Reader/Writer上加encoding的选项,注意编码的方向,在Reader中的encoding表示把数据从encoding转换成Unicode,writer就是把Unicode的字符转换成encoding格式的。2.用String.getByte()把字符串转换成指定编码。

常用的编码格式:ISO8859_1,这个是英文系统缺省的8bit编码,因为是8bit的,所以不会把汉字的高位删去,所以用它也是可以处理汉字的(我自己这么理解,总觉得有些不妥,但又不知道不妥在何处,还望高人指出)。GB2312和GBK,汉字编码,推荐使用GBK,它兼容GB2312并且支持更多汉字。UNICODE,一个大的字符集,不知是不是国际标准反正大家都支持,使用16位对每个字符编码,汉字虽然正合适,但英文却吃亏了,要用多一倍的空间来存储,所以很多人还是老大不乐意,写的程序不支持UNICODE.

JSP/Servlet的中文问题有两种解决办法:1.不在程序中进行编码转换,把这个工作交给浏览器,方法就是用javac –encoding GBK *.java来编译所有的bean,然后在JSP页面上加

或者是在HTML中直接加:

到底加那个,试试就知道了,我也搞不清楚了。

2.在程序中指定编码,用javac –encoding ISO8859_1 *.java来编译所有的bean,在涉及到中文显示的程序上加

str=new String(str.getBytes("ISO8859_1"));

上面两种方法不能混用,意思就是要么就是GBK,要么就是ISO8859_1,从里到外都一样就好了。

数据库JDBC的中文问题,一般只要按照数据库指定的编码进行转换,比如按照ISO8859_1读,ISO8859_1写,一般就没什么问题了。

虽然有这些编码上的心得,但是并不能解决我的问题。看来我的程序输入输出用的都是

ISO8859_1,我的问题跟编码没什么关系。是不是字体的问题呢?在Swing的组件中,字体总是那么几个,基本上是定死的,选那个都不行。但是我突然发现可以更改这些字体的配置,就是font.properties 这个文件,一般JDK都带了中文的字体配置文件,可能是font.properties.zh之类的,不同版本的JDK名字有些差别,你要做的就是用中文的配置覆盖font.properties文件。我满心欢喜的以为成功了,但是失败无情的又一次打击了我。不是这种方法不对,但是在Windows系统中,java能够比较自动的检查你的系统编码,

JDK1.1的文档呢。 使用最合适的字体配置文件,一般不需要你改动了,在JDK1.2之前确实是要这么改的,难怪那篇文章是

连font.properties也不灵了,唉,是不是JBuilder有问题呀?到了这儿,我不得不怀疑它了,虽然它从没让我失望过,我关掉JBuilder,拿起JDK命令行,哎呀!可爱的中文竟然出来了!简直是……莫名其妙呀,因为JBuilder也是用的这个JDK呀?没理由呀,我再次打开JBuilder,运行,乱码!怪事……我来看看……我把JBuilder里面的执行命令拷贝到DOS窗口里手动执行……没有中文……怪怪怪,我仔细对照我手敲的命令和JBuilder拷出来的命令,除了我用的是java它用的是javaw之外,别的几乎都一样,难道……这个java和javaw竟然会不一样?

唉……要我说什么呢,答案就是这个了,javaw会使用与java不同的Local配置进行工作,导致了我一直看不到中文,而java就是好好的。JBuilder也是好好的,没有问题,调用javaw也不是它的错,难道你想每次运行或者调试的时候蹦出个DOS黑框么?呵呵。这是JDK的一个Bug,我在java的网站上查到这个bug,描述的情况跟我的一样,然后Sun说这个Bug已经修复了,嘿嘿,简直就是扯淡!修复个茄子!Bug编号是:4629351.不信可以去看看。

但是难道我就不能在JBuilder里面看我可爱的中文了吗?好像JBuilder5的时候还能选择是用java还是javaw,现在好像没法儿选了。怎么才能让javaw支持中文呢?经过又是一番苦苦查找,竟然没有什么结果,郁闷!正当苦闷之时,突然想起当初配置过UNIX下的TOMCAT,好像加了些启动参数,就能让tomcat支持中文了,赶快翻出以前的文档,啊,幸好我当初写了工作心得,要不然又抓瞎了。其实道理很简单,就是给JAVA虚拟机加上一些属性:

-Dfile.encoding=GBK -Ddefault.client.encoding=GBK -Duser.language=zh -Duser.region=CN 把它跟在javaw的命令行后面当参数,哈哈,搞定!

在JBuilder中选择Project->Project Properties->run->edit->VM Parameters,填上就行了! 配置心得:

在JDK低版本和UNIX下,需要改动font.properties,让JAVA VM能够找到合适的字体来显示汉字。目前为止,javaw有Bug,只使用英文的Local,需要给VM加上属性才行正常显示中文。


第二篇:Java编程风格中文版


Java编码风格(规范)

20xx年02月

文档控制

创建更改记录

Java编程风格中文版

审阅人员

分发人员Java编码规范

Java编程风格中文版

Java编程风格中文版

-1-

Java编码规范

目录

创建更改记录................................................................................................................1

审阅人员........................................................................................................................1

分发人员........................................................................................................................1

1总则............................................................................................................................1

1.1保持原有风格(1)..............................................................................................1

1.2坚持最少惊讶的原则(2)..................................................................................1

1.3第一次就把事情作对(3)..................................................................................1

1.4记录所有非规范行为(4)..................................................................................1

2格式约定....................................................................................................................2

2.1缩进嵌套代码(5)..............................................................................................2

2.2拆分长行(6)......................................................................................................4

2.3包含空白空间(7)..............................................................................................6

2.4不要应用“难以忍受的”TAB键(8)...............................................................9

3命名约定....................................................................................................................9

3.1使用有意义的名字(9)......................................................................................9

3.2使用人们熟悉的名字(10)..............................................................................10

3.3慎重使用过长的名字(11)..............................................................................10

3.4加入元音字符(12)..........................................................................................10

3.5大写首字母缩略词的第一个字母(13)..........................................................11

3.6不要使用只通过大小写区分的名称(14)......................................................11

3.7使用公司域名的倒置小写形式作为包名的权限定词(15)..........................11

3.8使用单独小写的单词作为每个包的根名(16)..............................................12

3.9仅当新旧版本二进制兼容时,其包名可以使用相同的名字,否则请使用新名字(17)......................................................................................................................................12

3.10大写类和接口中每个单词的首字母(18)....................................................12

3.11用名词命名类(19)........................................................................................13

3.12复数化表示成组的属性、静态服务或常量的名字(20)............................13

3.13用名词或者形容词命名接口(21)................................................................14

3.14在方法命名中小写第一个单词并大写其他单词的首字母(22)................15

3.15用动词命名方法(23)....................................................................................15

-2-

Java编码规范

3.16遵循JavaBeans的约定来命名访问属性的方法(24)................................16

3.17在变量命名中小写第一个单词并大写其他单词的首字母(25)................16

3.18应用名词命名变量(26)................................................................................17

3.19采用复数形式命名集合引用(27)................................................................17

3.20为不重要的临时变量建立并使用一套标准的名字(28)............................18

3.21用“this”限定成员变量来与本地变量区分(29).......................................18

3.22在构造函数或“set”方法中将参数赋值给成员变量时,用与成员变量相同的名称作为参数命名(30)......................................................................................................19

3.23命名常量时,每个单词用大写字母且每两个单词用下划线分隔(31)....19

4文档约定..................................................................................................................20

4.1为你代码的使用和维护人员书写文档(32)..................................................20

4.2保持注释和代码同步(33)..............................................................................20

4.3应用主动语态,忽略无用的单词(34)..........................................................20

4.4应用文档注释来描述编程接口(35)..............................................................20

4.5应用标准注释来隐藏代码而不是删除(36)..................................................22

4.6应用单行注释来解释实现细节(37)..............................................................22

4.7在编写代码前描述编程接口(38)..................................................................23

4.8为公有、受保护、包和私有的成员建立文档(39)......................................23

4.9为每个包提供概述(40)..................................................................................23

4.10为包的每个应用程序或组提供概述(41)....................................................24

4.11对所有的文档注释使用统一格式和组织结构(42)....................................24

4.12将关键字、标识符和常量放在<code>……<code>标签中(43)................24

4.13将代码放入<pre>…</pre>标签中(44)......................................................25

4.14在标识符第一次出现的时候用{@link}标签(45)......................................25

4.15为javadoc标签创建和使用一套固定的顺序(46)....................................26

4.16叙述使用第三人称形式(47)........................................................................28

4.17编写独立的概述(48)....................................................................................28

4.18省略行为或服务概述中的主题(49)............................................................29

4.19省略事物描述中的主题和动词(50)............................................................30

4.20当提及当前类的实例时用“this”而非“the”(51).................................30

4.21不要为方法或构造函数增加圆括弧,除非你想指定某特殊意义(52)....31

4.22为每个类、接口、域和方法提供概述(53)................................................31

4.23充分描述每个方法的标记(54)....................................................................31

-3-

Java编码规范

4.24包含示例(55)................................................................................................31

4.25为前置、后置和不变条件编写文档(56)....................................................32

4.26为已知的缺陷和不足编写文档(57)............................................................32

4.27为同步语义书写文档(58)............................................................................33

4.28仅添加能够帮助理解你代码的内部注释(59)............................................33

4.29描述代码为什么这么做,而不是在做什么(60)........................................33

4.30避免使用行尾注释(61)................................................................................34

4.31用行尾注释解释局部变量声明(62)............................................................34

4.32创建并使用一组关键字来标明尚未解决的问题(63)................................34

4.33在嵌套程度高的控制结构中标记出嵌套结束位置(64)............................34

4.34如果两个case标记之间没有break语句,则在它们之间加入“fall-through”注释(65)......................................................................................................................................35

4.35标记空语句(66)............................................................................................35

5编程约定..................................................................................................................36

5.1将表示基础数据类型的类声明为final(67)...............................................36

5.2通过本地类型和其他的具体类型来创建具体类型(68)..............................36

5.3定义小的类和方法(69)..................................................................................37

5.4定义子类,以便能够使用超类的地方都可以使用子类(70)......................37

5.5将所有字段私有化(71)..................................................................................41

5.6使用多态来代替instanceof(72).................................................................41

5.7以java.lang.Object包装通用类,提供静态类型检查(73)....................41

5.8以类的形式封装枚举类型(74)......................................................................42

5.9应用等价的方法替代重复、复杂的表达式(75)..........................................43

5.10使用块语句代替控制流结构中的表达式(76)............................................43

5.11使用括号明确操作顺序(77)........................................................................44

5.12在switch最后一个case语句中使用break语句(78)............................44

5.13使用equals(),而不是==来检测对象的对等关系(79)...........................45

5.14构造状态有效的对象(80)............................................................................46

5.15不要在构造函数中调用一个非final的方法(81)....................................46

5.16用嵌套的构造函数来消除冗余(82)............................................................46

5.17应用不受检查、运行时异常来报告可能发生在程序逻辑中出错的严重未查明的错误

(83)..........................................................................................................................47

5.18应用检查异常来报告可能发生、而在正常情况下很少发生的错误(84)47

-4-

Java编码规范

5.19应用返回代码报告可预知的状态变化(85)................................................47

5.20仅转换异常来添加信息(86)........................................................................48

5.21不要私自处理运行时或错误异常(87)........................................................48

5.22应用finally块来释放资源(88)................................................................49

5.23按照约定编程(89)........................................................................................49

5.24应用无用代码消除机制来实现断言(90)....................................................50

5.25应用断言来捕获代码中的逻辑错误(91)....................................................51

5.26应用断言来检测方法的前置和后置条件(92)............................................52

5.27仅在适当的地方使用线程(93)....................................................................52

5.28避免同步(94)................................................................................................53

5.29应用同步包装器来提供同步接口(95)........................................................53

5.30如果方法中包含不需要同步的重要操作,那么不要同步整个方法(96)54

5.31读写实例变量时避免不必要的同步(97)....................................................54

5.32使用notify()而不是notifyAll()(98)....................................................55

5.33为同步初始化使用双重检查模式(99)........................................................55

5.34使用懒惰初始化(100)..................................................................................56

5.35避免创建不必要的对象(101)......................................................................56

5.36重新初始化并重复使用对象来避免创建新对象(102)..............................56

5.37把优化工作放到最后(103)..........................................................................576包约定......................................................................................................................57

6.1将经常使用、变化、发布或者相互依赖的类放置在同一包中(104)........57

6.2将不稳定的类和接口放在单独的包中(105)................................................58

6.3避免让不易于变化的类依赖于易于变化的类(106)....................................58

6.4最大化的抽象已达到最大的稳定性(107)....................................................58

6.5将高层次的设计和架构作为稳定的抽象,组织为稳定的包(108)............59

6.6概要......................................................................................................................597参考文献..................................................................................................................62

-5-

Java编码规范

1总则

对于职业的Java开发人员,写出运行良好的软件是至关重要的,但是同时他还应该考虑其他问题。所有优秀的软件都运行良好。但是卓越的软件有自己的编码风格,它是可预测的、健壮的、可维护的、可支持的并且可扩展的。

1.1保持原有风格(1)

当修改原有软件时,修改后的代码应该保持原有代码的风格。不要试图在修改时引入一种新的编码风格,也不要试图为了迎合新的编码风格而重写原有软件。因为在同一份代码中使用不同的编码风格,使得代码难以阅读和理解。在重写代码时,简单的修改编码风格,会导致代价惨重的缺陷,而本来这些是可以避免的。

1.2坚持最少惊讶的原则(2)

最少惊讶原则建议出你避免做一些让软件用户感到惊奇的事。这就意味者,软件展现的交互和行为方式必须是可预示的并且一致的。否则,说明文档必须对所有的非常规用法或行为明确的指示出来,并给出正当理由。

将用户在使用软件中遇到意外情况的可能性降到最低,必须在java软件的设计、实现和文档编写中遵循以下几点:

?简单性:构造简单的类和方法。确定你需要做多少才能满足用户的需求。

?清晰性:确保每一个类、接口、方法、变量和对象具有明确的用途。说明哪里、

何时、何种原因和如何使用它们。

?完整性:提供任何合理用户期望获取和使用的最低限度的程序功能。编写完整的

说明文档,记录所有的特征和功能。

?一致性:相似的实体在外观和行为上应该一致,反之亦然。尽可能建立并遵守标

准。

?健壮性:为错误和异常作出预测,并将解决方法写入文档。不要隐藏错误也不要

等着用户自己去发现错误。

1.3第一次就把事情作对(3)

将这些规则应用在所有你写的代码中,而不仅仅在产品本身的代码上。通常,许多段原型代码或者试验代码会被写入到最终产品中,所以你应该预见这种可能性。即使这些不会成为产品代码的一部分,你的代码总还是会被其他人读到。任何阅读你代码的人,都因你从在一开始就一贯应用这些规则而赞美你的职业作风和先见之明。

1.4记录所有非规范行为(4)

没有任何标准是完美的,也没有任何标准是普遍通用的。有时候你会发现你处于必须偏离已经建立的标准体系的情况。

在你决定忽略一个规则前,你首先应该确定你理解这个规则存在的原因和不用这个规北京宏博远达科技有限公司-1-

VCI则会出现的结果。如果你必须违反一个规则,那么你需要将你的原因记录下来。这是第一守则。

2格式约定

2.1缩进嵌套代码(5)编码规范

改善代码可读性的一种途径是:把单独的语句聚合成块语句,统一缩进每一块语句,从而使其与其周围的代码划分开来。

如果你用一种JAVA开发环境来产生代码,那就用此环境所提供的缩进模式。如果你手工书写代码,用2(或4)个空格来保证可读性,并且不会占去太多的空间。classMyClass{

voidfunction(intarg){

if(arg<0){

for(intindex=0;index<=arg;index++){

}

}

}

}

除了缩进块语句的内容,你还需要缩进标签后的语句,从而使标签很容易的被注意到:voidfunction(intarg){

loop:

for(intindex=0;index<=arg;index++){

switch(index){

case0:

//

breakloop;//exittheforstatement

default:

//

Break;//exittheswitchstatement

}

}

}

把每个块语句开始的大括弧“{”放置在块语句所在行最后字符的后面。将块结束的大括弧“}”放置在块后另起一行的第一个字符处。下面的例子阐述了这条规则如何应用在各种JAVA的定义和控制构造函数中。

类定义:

-2-

CIpublicclassMyClass{//

}

内部类定义:

publicclassOuterClass{//

classInnerClass{//

}

//

}

方法定义:

voidmethod(intj){}

静态块:static{

//

}

For循环语句:

for(inti=0;i<j:i++){//

}

If和else语句:if(j<0){//

}elseif(j>0){//

}else{

//

}

Try,catch,finally块:try{

//

}catch(Exceptione){编码规范

-3-V

VCI//

}finally{

//

}

Switch语句:

switch(value){

case0:

//

break;

default:

//

break;

}

匿名内部类:

button.addActionListener{

newActionEventListener(){

publicvoidactinPerformed(){

//

}

}

}

While语句:

while(++k<=j){

//

}

Do-while语句:

do{

//

}while(++k<j);编码规范

如果你管理一个开发团队,你应该建立一套让每个成员遵守的缩进标准,而不是让各个员工选择自己的缩进数量和形式。

尽管你的组织可能偏好与三个或四个空格,但我们推荐的两空格缩进出现在多数的通用标准中。

2.2拆分长行(6)

当基于window的流行编辑器可以通过水平滚动的方式处理长行源代码时,打印机不得

-4-

VCI编码规范不通过删减、覆盖或者分页打印那些超过打印机最大宽度的行。为了保证你的代码在打印后仍然是易读的,你应该限制你源代码的最大长度,使其不超过打印环境能够支撑的,典型的长度是80或者132个字节。

首先,不要将多条程序语句写在同一行中,这样会使得行的字节数超过最大允许的字节数。如果两条程序语句放在同一行中:

doublex=Math.random();doubley=math.ran

dom();//TooLong!

插入一行将两句分为两行书写。

doublex=Math.random();

doubley=Math.random();

其次,如果一行语句因为一个复杂的程序语句而过长:

doublelength=Math.sqrt(Math.pow(Math.random(),

2.0)+Math.pow(Math.random(),2.0);//TooLong!

则将其分解成多行小的程序代码。应用单独的行来将各分表达式计算得到的值存储到临时变量中。

doublexSquared=Math.pow(Math.random(),2.0);

doubleySquared=Math.pow(Math.random(),2.0);

doublelength=Math.sqrt(xSquared+ySquared);

最后,如果长行不能应用以上两条准则进行缩短,则应用下面的规则进行分解、换行和缩进:

步骤一:

如果顶层表达式行包含一个或多个逗号时:

doublelength=Math.sqrt(Math.pow(x,2.0),math

.pow(y,2.0));//TooLong!

这时,建议在逗号的后面对行进行分解,同时使得逗号后面的语句与逗号前语句的第一个字符对齐。

doublelength=Math.sqrt(Math.pow(x,2.0),

Math.pow(y,2.0));

步骤二:

如果顶层表达式行中不含逗号:

classMyClass{

privateintfield;

//

booleanequal(Objectobj){

returnthis==obj||(objinstanceofMyClass

-5-

VCI&&this.field==obj.field);//TooLong!

}

//

}编码规范

如果在每个运算符中存在多于一个的相等低优先运算符,则建议在最低优先运算符的前面将行分解。

classMyClass{

privateintfield;

//

booleanequals(Objectobj){

returnthis==obj

||(thisobjinstanceofMyClass

&&this.field==obj.field);

}

//

}

步骤三:

根据需要,重复使用步骤二和步骤三,直至由原语句表达式产生的行的长度小于最大允许的长度。

2.3包含空白空间(7)

白空间即页面中没有可见字符的区域。含有很少空白空间的代码可读性很差并且难于理解,所以需要应用大量的空白空间来清楚的描述方法、注释、代码块和表达式。应用一个空格来分隔:

?右圆括弧或大括弧和其后面的关键字之间,关键字与左圆括弧或大括弧之间,或者右圆括弧和左大括弧之间需要加入一个空格进行分隔。

for(…){

//

}

while(…){

//

}

do{

//

-6-

VCI}while(…);

swith(…){

//

}

if(…){

//

}elseif(…){

//

}else{

//

}

try{

//

}catch(…){

//

}finally{

//

}编码规范

?除“.”运算符外的任意二元运算符前面或者后面都需要加入一个空格进行分隔。doublelength=Math.sqrt(x*x+y*y);

doublexNorm=length>0.0?(x/length):x;

应用空白行进行分隔:

?方法中的每个逻辑分段之间需加入空白行分隔。

voidhandleMessage(Messagemessage){

DataInputcontent=message.getDataInput();

intmessageType=content.readInt();

switch(messageType){

caseWARNING:

//

-7-

VCIbreak;

caseERROR:

//

break;

default:

//

break;

}

}

?类或接口定义中的每一个成员之间需要加入空行来分隔。publicclassFoo{

/**

*Definesaninnerclass.

*/

classInnerFoo{

//

}

/**

*TheBarassociatedwiththisFoo.

*/

privateBarbar;

/**

*

*/

Foo(Barbar){

this.bar=bar;

}

}

?源文件中的每个类和接口定义之间需要加入空行进行分隔。/*

-8-编码规范

VCI*…filedescription…

*/

packagecom.company.xyz;

/**

*…interfacedescription…

*/

interfaceFooInterface{

//

}

/**

*…classdescription…

*/

publicclassFooimplementsFooInterface{

//

}

2.4不要应用“难以忍受的”TAB键(8)编码规范

许多开发程序员应用TAB字符来缩进和对齐其源代码,他们没有认识到TAB字符是随环境变化而变化的字符。这样的源代码,当其在原有的编辑环境查看时,代码按正确的格式显示,但把其放入对TAB字符具有不同解释的环境中时,代码按难以阅读的无格式显示。提示

应用空格代替TAB字符来缩进和对齐源文件来避免上述问题。你可以通过简单的方法来实现,比如应用空格条来取代TAB键,或者配置你的编辑器将TAB字符替换成空格符。许多编辑器提供“灵巧”缩进的功能,如果其缩进采用的是TAB字符,则需要你取消此项功能。

你公司应该按照规则2.1设置一种通用的缩进长度,并将其一贯的应用在所有的JAVA代码中。

3命名约定

下述的命名约定与SUN公司在JSDK中所采用的命名约定相同。

3.1使用有意义的名字(9)

当你命名类、变量、方法或者常量时,应用一个对最后阅读你代码的程序员有意义的

-9-

VCI编码规范并且持久的名字。应用有意义的词语来命名,而不要使用对定义命名实体没有意义的单个字符或者通用名。

在下面代码中,变量“a”和常量“65”的意义是不明确的。

if(a<65){

}else{

y=0;

}

当使用有意义的名称时,这段代码更易于被人理解。

if(age<RETIREMENT_AGE){

yearsToRetirement=RETIREMENT_AGE–age;

}else{

yearsToRetirement=0;

}

这条规则唯一的例外是对临时变量。临时变量的上下文提供了足够的信息来确定它们的意义。例如,作为计数器的变量或者循环中索引的变量。

for(inti=0;i<numberOfStudents;i++){

enrollStudent(i);

}

很多变量的定义和应用场景出现的频率足以将其标准化。

(详情请看规则28)

3.2使用人们熟悉的名字(10)

使用目标领域中存在的术语进行命名。如果你的用户将client称为customer,则应用Customer作为类的名字,而不用Client。许多程序员通常在为概念创建新的或者通用的术语上犯错,因为合适的术语已经在目标的行业或领域已经存在。

3.3慎重使用过长的名字(11)

对象的名字必须能充分描述其意图。但如果一个类、接口、变量或方法具有过长的名字,此时会让人觉得此对象可能试图完成更过的工作。

为了避免通过简单的组合而为一实体创建包含少量信息但很长的名字,首先应该重新考虑其设计和意图。重构后的实体可能产生新的类、接口、方法或者变量,这些新产生的对象可以准确地通过现有的简单而有意义的术语来命名。

3.4加入元音字符(12)

缩写降低了你代码的可读性的,当多个有意义的名字缩减为相同的缩写时,还会增加你代码的多义性。

不要试图通过移出原因字母缩写名字。这样会降低代码的可读性,如果多个有意义的

-10-//“a”描述的是什么属性?y=65–a;//这里将要计算的是什么?

VCI名字缩减为相同的辅音时,则增加了代码的多义性。

随便一个阅读者能够理解下面定义中名字的意思。编码规范

publicMessageappendSignature(Messagemessage,Stringsignature){//

下面的缩写则很难被人读懂。

publicMsgappndSgntr(Msgmsg,Stringsgntr){

//

}

如果你想通过简单的移除原音字符来缩短长名字时,你应该首先考虑原始的名字是否合适。查看规则11.

3.5大写首字母缩略词的第一个字母(13)

这种风格可以通过大写字母作为单词的分隔符来消除混淆,尤其是多个首字母缩略词首尾相连时。

setDSTOffSet()

loadXMLDocument()

这条规则不能应用在以下情况中。

?当首字母缩略词出现在常量中时,不能使用此规则。因为常量的名字只由大写字母组成(查看规则31)。

staticfinalStringXML_DOCUMENT=“txt/xml”;

?当首字母缩略词作为方法、变量或参数名字开头时,不能使用此规则。因为这些名字以小写字母开始。(查看规则22和规则25)

3.6不要使用只通过大小写区分的名称(14)

JAVA编辑器可以通过大小写来区分名称,但是读者却很难注意到大小写名称的区别。例如,在变量名称theSqlInputStream存在的范围内,最好不要出现以

theSQLInputStream命名的变量。如果两个变量同时出现在同一范围内,当人们试图去阅读并理解这段代码时,从名字代表的意思分析,任何一个名字都可以隐藏另一个名字的含义。

包命名

3.7使用公司域名的倒置小写形式作为包名的权限定词(15)

发布给其他组织的所有包都要包含软件编写组织的倒序小写形式域名。例如,一个公司的名字是ROGUEWAVESOFTWARE,公司的域名是roguewave.com,想要发布一个名为server应用服务程序,这时ROGUEWAVE公司应该将此包命名为com.roguewave.server。

SUN公司限制使用java和javax作为包的限定词。包限定词java只能被java原厂商使用,从而提供与标准java库相兼容的实现方式。SUN公司保留javax这个名字,以用其检验其java扩展部分的质量。

-11-setDstOffSet()loadXmlDocument();

VCI3.8使用单独小写的单词作为每个包的根名(16)编码规范

合格的包名的必须包含一个单独小写的单词,这个单词能够清楚的表述包的目的和用途。一个包名也可以包含一个有意义的缩写词,如为人们认可的标准JAVA包中的java.io和java.net。

3.9仅当新旧版本二进制兼容时,其包名可以使用相同的名字,否则请使用新名字(17)这条规则的目的是保证两个具有相同限定名的JAVA类在二进制和行为上是相互兼容的。

JAVA执行模型在运行时,将类的客户绑定在类的实现上。意思是除非你采用这个约定,否则你将没有办法保证你现在应用程序使用的版本,与你建立应用程序的使用并测试过的版本是同一版本。

提示:

如果创建包的新版本与旧版本在二进制或行为上不兼容,应该改变包的名字。重命名可以通过很多种方法完成,即安全又容易的办法是在包名中加入一个版本号,在每次不兼容改变时升级版本好即可以完成重命名。

com.roguewave.server.v1

com.roguewave.server.v2

……

这种重命名方法的唯一缺点是,包的客户端与应用之间的依赖关系被硬编码在客户端代码中了。包的客户端只有通过修改客户端的代码来绑定包的新版本。

类型命名

3.10大写类和接口中每个单词的首字母(18)

大写为名字中单个单词的分割提供了视觉的提示。首字母大写提供了区分类名或接口名与变量名的机制(查看规则25)。

publicclassPrintStreamextendsFilterOutputStream{

//

}

publicinterfaceActionListenerextendsEventListener{

//

}

类命名

3.11用名词命名类(19)

名定义对象或事物,这些对象或事物通过名词来识别。

-12-

VCIclassCustomerAccount{

//

}

publicabstractclassKeyAdapterimplementsKeyListener{

//

}

3.12复数化表示成组的属性、静态服务或常量的名字(20)编码规范

为具有成组相关属性、静态服务或者常量的类命名,应该使用相应属性、服务或者静态变量的复数形式。

java.awt.font.LineMetrics是如何定义一组相关属性对象的例子。

/**

*The<code>LineMetrics</code>classgivesaccesstothemetrics*needtolayoutcharactersalongalineandtolayoutofaset*oflines.

*/

publicclassLineMetrics{

publicLineMetrics();

publicabstractintgetNumChars();

publicabstractfloatgetAscent();

publicabstractfloatgetDescent();

publicabstractfloatgetLeading();

publicabstractfloatgetHeight();

}

java.beans.Beans类是如何定义了一组相关静态服务的例子。

/**

*The<code>Beans</code>classprovidessome

*generalpurposebeanscontrolmethods.

*/

publicclassBeans{

publicstaticObjectinstantiate(…){...};

publicstaticObjectgetInstanceOf(…){…};

publicstaticbooleanisInstanceOf(…){…};

publicstaticbooleanisDesignTime(){…};

publicstaticbooleanisGuiAvailable(){…};

publicstaticvoidsetDesignTime(…){…};

-13-

VCIpublicstaticvoidsetGuiAvailable(…){…};}

java.sql.Types类是如何定义一组相关静态变量的例子/**

*The<code>Types</code>classdefinesconstants*thatareusedtoidentifySQLtypes.

*/

publicclassTypes{

publicfinalstaticintBIT=-7;

publicfinalstaticintTINYINT=-6;

publicfinalstaticintSMALLINT=5;

publicfinalstaticintINTEGER=4;

publicfinalstaticintBIGINT=-5;

publicfinalstaticintFLOAT=6;

publicfinalstaticintREAL=7;

publicfinalstaticintDOUBLE=8;

publicfinalstaticintNUMERIC=2;

publicfinalstaticintDECIMAL=3;

publicfinalstaticintCHAR=1;

}

接口命名

3.13用名词或者形容词命名接口(21)

接口提供了一个对象实体提供服务的声明或者对象能力的描述。应用名词命名表现为服务声明的接口。

publicinterfaceActionaListener{

publicvoidactionPerformed(ActionEvente);}

应用形容词命名表现为描述能力的接口。

publicinterfaceRunnable{

publicvoidrun();

}

publicinterfaceAccessible{

publicContextgtetContext();

}

方法命名

-14-编码规范

VCI3.14在方法命名中小写第一个单词并大写其他单词的首字母(22)编码规范

大写在命名中提供了分隔单个单词的视觉提示。小写首字母提供了区分构造函数和一般方案的机制。

classMyInmageextendsImage{

publicMyImage(){

//

}

publicvoidflush(){

//

}

publicImagegetScaledInstance(){

//

}

}

3.15用动词命名方法(23)

方法和操作通常是定义行动,而行动通常是动词。

classAccount{

privateintbalance;

……

publicvoidwithdraw(intamount){

deposit(-1*amount);

}

publicvoiddeposit(intamount){

this.balance+=amount;

}

}

3.16遵循JavaBeans的约定来命名访问属性的方法(24)

JavaBean规范针对访问JavaBean应用的属性制定了标准的约定。在任何类中,无论类是否应用了Bean,都要应用此项约定来命名方法。

JavaBean通过以“is”开始的方法名来访问boolean型属性。

booleanisValid(){

returnthis.isValid;

-15-

VCI}

JavaBean通过以“get”开始的方法名来读取其他类型的属性。

StringgetName(){

returnthis.name;

}

读取索引属性的方法带有一个int型参数。

StringgetAlias(intindex){

returnthis.alias[index];

}

JavaBean通过以“set”开头的方法来设置Boolean类型和其他类型属性值voidsetValid(booleanisValid){

this.isValid=isValid;

}

voidsetName(Stringname){

this.name=name;

}

设定索引属性的方法带有一个索引参数。

voidsetAlias(intindex,Stringalias){

this.aliases[index]=alias;

}编码规范

JDK严格遵守这些约定。当暴露Bean的组成属性时,标志is/get/set时需要的。除非你定义了一个BeanInfo类。

变量命名

3.17在变量命名中小写第一个单词并大写其他单词的首字母(25)

大写在命名中提供了分隔单个单词的视觉提示。小写首字母提供了区分变量名和变量名的机制(查看规则18)。

classCustomer{

……

privateAddressaddress;

privatePhonedaytimePhone;

……

publicAddresssetAddress(Addressaddress){

AddressoldAddress=this.address;

-16-

VCIthis.address=address;

returnoldAddress;

}

……

publicvoidsetDaytimePhone(PhonedaytimePhone){

……

}

……

}

3.18应用名词命名变量(26)

变量指向对象或者事物,而对象或事物通过名词识别。

classCustomer{

…..

privateAddressbillingAddress;

privateAddressshippingAddress;

privatePhonedaytimePhone;

privateVectoropenOrders;

……

}

3.19采用复数形式命名集合引用(27)编码规范

为成员和变量的集合对象命名,应该符合包含在集合中对象类型的复数形式。这样命名可是使读者能够区分你代码中代表符合值的变量和代表单一值的变量。Customer[]customers=newCustomer[MAX_CUSTOMER];

voidaddCustomer(intindex,Customercustomer){

this.customers[index]=customer;

}

VectororderItems=newVector();

voidaddOrderItem(orderItemorderItem){

this.orderItems.addElement(orderItem);

}

3.20为不重要的临时变量建立并使用一套标准的名字(28)

-17-

VCI编码规范你应该使用全部的描述性名字为大多数变量命名。但是许多在JAVA代码中出现很频繁的变量类型具有公共的速记名称,你需要选择速记名称来替代。下面的表中列举了一些例子:

Character

Coordinate

Exception

Graphics

Object

Stream

String

成员变量

3.21用“this”限定成员变量来与本地变量区分(29)

为了更容易的区分本地变量和成员变量,应用“this”来限定成员变量。publicclassAtomicAdder{

privateintcount;

publicAtomicAdder(intcount){

this.count=count;

}

publicsynchronizedintfetchAndAdd(intvalue){

inttemp=this.count;

this.count+=value;

returntemp;

}

publicsynchronizedintaddAndFetch(intvalue){

returnthis.count+=value;

}

}

参数命名

3.22在构造函数或“set”方法中将参数赋值给成员变量时,用与成员变量相同的名称作

-18-c,d,ex,y,zegoin,out,inOuts

VCI为参数命名(30)编码规范

用本地变量来隐藏实例变量的名称通常被认为是不好的方式。但是这种方法也存在着许多好处。应用相同的名字可以减少再为其提出一个不同命名的责任。同时,应用相同的名字还可以为读者提供一个微妙的线索,即这个参数是为了具有相同名字的本地变量赋值的。

classDude{

privateStringname;

publicDude(Stringname){

this.name=name;

}

publicsetName(Stringname){

this.name=name;

}

}

常量命名

3.23命名常量时,每个单词用大写字母且每两个单词用下划线分隔(31)常量名称通过大写来区分常量和其他非最终变量。

classByte{

publicstaticfinalbyteMAX_VALUE=255;

publicstaticfinalbyteMIN_VALUE=0;

publicstaticfinalClassTYPE=Byte.class;

}

4文档约定

4.1为你代码的使用和维护人员书写文档(32)

为你代码公用的编程接口书写文档,从而其他人正确高效的使用你的代码。为你代码的私有接口和内部应用细节书写文档,从而使得其它人能够维护和增强你的代码。

总认为完全不熟悉你代码的人最终需要阅读并理解你的代码。事实上,很长时间以后,你的代码对很多人来说会变得陌生,这个人很可能就是你自己。

4.2保持注释和代码同步(33)

当代码和注释不一致时,它们可能都是错误的。--NormScbryer,BellLabs

-19-

VCI当你修改代码时,确定你也更新了所有相关的注释。

代码和文档共同构成一个软件,所以同等的对待它们中的每一部分。

4.3应用主动语态,忽略无用的单词(34)编码规范

注释是一种散文形式。强有力的、清晰的和简明扼要的语言对技术性文档尤为有益。注释类型

JAVA支持三种类型注释:

?以“/**”开始,以“*/”结束的文档注释:

/**

*一条文档注释

*/

?以“/*”开始,以“*/”结束的标准或C语言类型注释:

/*

*一条标准注释

*/

?一种单行或结束行注释,其以“//”开始并且所有注释只在此单行中。//一条单行注释

classMyClass{

intmyField;//一条结束行注释

}

每种注释类型为一类特定的目的服务,你应该为每类特定的目的以一贯的风格应用每种注释类型。

4.4应用文档注释来描述编程接口(35)

在你的代码中,你可能放置文档注释在任何类、接口、方法、构造函数或者字段声明的前面。这些注释提供信息,javadoc应用程序应用这些信息产生HTML格式类的说明或者应用编程接口(API)文档。为了创建这些文档,javadoc应用程序以分析一组java源文件中出现的所有声明的方式,读取相应的注释。javadoc应用这些信息生成一组相应的HTML页,它们默认描述这些文件中的公有的和受保护的类、内部类、接口、构造函数、方法和参数。

javadoc只能识别刚好出现在类、接口、构造函数或者参数定义前面的文档注释。javadoc忽略任何出现在方法体中的文档注释,所以不要以这种方式应用文档注释。javadoc只允许每个声明语句对应一块文档注释,所以不要尝试为每个声明使用多块文档注释。

文档注释的主要目的是在客户和服务器之间定义一个编程约定。与某一方法联系的文档应该描述此方法调用者可以信赖的所有行为方面,,而不是尝试描述应用细节。

-20-

VCI编码规范下述代码阐述了应用文档注释来注释类。这个类声明了一个内部类、一个参数、一个方法和一个构造函数。

/**

*类<code>Rectangle<code>描述了一个通过方法location(x,y)和方法

*(dimension(x,h)定义的矩形。

*……

*/

publicabstractclassRectangle2DextendsRectangularShape{

/**

*类<code>Double<code>定义了通过一对坐标确定的矩形。

*……

*/

staticclassDoubleextendsRectangle2D{……}

……

/**

*位掩码表示位于此Rectangle2D下面的点……

*/

staticintOUT_BOTTOM;

/**

*在此Rectangle2D中增加一个Rectangle2D

*/

publicvoidadd(Rectangle2Dr){……}

……

/**

*这是一个抽象类,它不能被直接实例化……

*/

protectedRectangle2D(){……}

}

4.5应用标准注释来隐藏代码而不是删除(36)

当你希望暂时从编译器中隐藏代码时,应用标准的C类型注释来隐藏它们,而不是从源文件中删除这些代码。你只能应用这种注释类型来注释掉一段没有其他注释块嵌入的代码。

避免任何关于注释块嵌套的问题,因为嵌套注释块让人看起来像文档注释。除了暂时

-21-

VCI隐藏代码,请不要应用这种类型的注释。

下述代码段示范了如何应用这种类型的注释来隐藏一段功能的定义。/**

*…

*@deprecated

*/

/*编码规范

我暂时移出这个方法,因为人们有时不赞同此方法。同时我想确定其他包是否还应用这个方法!-J.Kirkon9Dec1997

publicvoidthisOldFunction(){

//Therehasgottobeabetterway!

}

*/

4.6应用单行注释来解释实现细节(37)

应用一个或多个单行注释来说明:

?

?

?

?

?

?特殊变量或表达式的目的。实现层的设计决定。复杂算法的源素材。错误补丁或迂回工作法。更加优化或改进的代码。已知的问题、限制或缺陷。

编写代码同时编写文档,可以将嵌入注释的需求降到最低。不要增加简单重复代码工作的注释。添加的注释必须包含有用的信息。

doubletotalCoas;//Usedtototalinvoid.

//Applythediscounttoallinvoicesover$1000.

if(totalCost>1000.0){//:TODO:Useconstants?

//这个折扣是硬编码的,因为目前所有的客户都用相同的折扣率。

//如果有位顾客需要不同的折扣,或者想用多中折扣,我们将用一个//变量替换这个常量

totalCost=totalCost*DISCOUNT;

}

文档注释

-22-

VCI4.7在编写代码前描述编程接口(38)编码规范

创建API参考文档的最佳时机是在开发过程的早期。应用文档或者“doc”注释来定义每个类或者接口的目的、用法和行为,这些类和方法将是构成潜在设计解决方案的组成部分。当新引入的类型的目的和基本原理你尚未清晰时,请将它们记录下来。不要认为你必须在产生文档前完成每个方法的实现-javadoc实用工具可以在java源文件中运行,哪怕类的方法只包含基本框架而没有被实现。这就意味这你可以在实现的最初阶段,在编写方法体之前,书写文档注释并运行javadoc。

对于类型及其方法和字段的最初描述,不仅为应用此类型的开发人员提供指导,也应为此类型的最终API参看文档打下基础。当公用接口的实现细节被定义的更好、更清楚时,实现类的程序员还会对原始文档做进一步的详细阐述。

4.8为公有、受保护、包和私有的成员建立文档(39)

为所有的成员提供文档注释,包含那些包级、受保护和私有访问权限的成员。这样就有利于生成详细的、实现层的文档。开发人员在实现改进或打补丁之前,必须要学习和理解你的代码,他们会感激你为所有类成员提供高质量的文档,而不仅仅是公有成员的远见。

4.9为每个包提供概述(40)

javadoc实用工具提供在其产生的文档中包含包描述的机制。应用javadoc的这种功能为每个你创建的包提供概述和总结。

为包创建描述时,必须创建名为package.html的注释文件,同时将此文件和包的其他源文件一同放在包所在目录下。javadoc会在目录中自动搜索此文件。

包的注释文件包含HTML文档,而不是java源代码。包描述必须写在HTML的<body>标签之内。javadoc把出现在<body>……<body>中的第一个语句或词组作为包的概要描述,这和处理普通文档注释是一样的。

除了{@link}标签,你可以在包的描述中应用javadoc的任何标签。出现在包描述的任何@see标签必须使用完全符合的名称。

4.10为包的每个应用程序或组提供概述(41)

javadoc实用程序可将不受包控制的概述包含在其产生的文档中。应用这种机制,为你创建包的每个应用程序和包编写概述。

要生成概述,必须创建一个概述的注释文件,这个文件的名字没有规定,但必须以“.html”结束,例如overview.html。要将这个文件包含在文档中,你必须通过设置-overview参数来告诉javadoc文件的位置。

概述注释文件包含HTML文档,而不是java源代码。概述必须包含在HTML<body>标签之内。javadoc将<body>……<body>标签里出现的第一个语句或短语作为应用或包组的概述,这和处理普通文档注释是相同的。

除了{@link}标签外,你可以在描述中应用任何的javadoc标签。任何出现在概述中的@see标签,必须应用完全有资格的名字。

-23-

VCI文档类型编码规范

在这一节中列出的“doc”注释格式约定都是严格遵循SUN公司采取并发布的约定。

4.11对所有的文档注释使用统一格式和组织结构(42)

格式得当的文档注释包含一个或多个javadoc标签的描述。

每条文档注释应采用如下格式:

?

?

?

?

?

/**

*这个实体的描述性文字

*

*@tag这个标签的描述文字

*/

以下规则可以为创建高质量、可维护的文档注释提供额外的指导。

4.12将关键字、标识符和常量放在<code>……<code>标签中(43)

将文档中的关键字、包名、类名、接口名、方法名、字段名、参数名、常量名和常量值放入到HTML<code>……</code>标签中。

/**

*Allocatea<code>Flag</code>object

*representingthe<code>value</code>argument.

*……

*/

publicFlag(booleanvalue){……}

<code>…</code>标签告诉HTML浏览器将其中的内容以与普通文本不同的方式呈现出来。那些元素会更醒目。

4.13将代码放入<pre>…</pre>标签中(44)

将文档注释中出现的代码放在HTML<pre>……</pre>标签中。

/**

*…

*Thefollowingexampleusersa

*<code>Class</code>objecttoprinttheclass

-24-缩写注释第一行,对齐起始-注释标记“/**”中的斜杠和包含相关定义那一行的第一个字符。之后每一行都要以“*”开始,并使此“*”与开始注释标记中的第一个星号对齐。用单个空格来分隔星号和星号后面的描述性文字或标签。在同一段注释的描述性文字和javadoc标签之间插入一空行。在每段注释的结尾处使用结束注释标记“*/”,结束注释标记中的星号要与注释段中的其他星号对齐。

VCI*nameofanobject.

*

*<pre>

*voidprintClassName(Objecto){

*

*

*

*

*}

*</pre>

*…

*/

publicfinalclassClass{……}System.outp.println(“Theclassof“+o+“is“+o.getClass().getName());编码规范

<pre>……</pre>标签告诉HTML浏览器保持注释格式化之前的原有格式,包含缩进和行结束格式。

4.14在标识符第一次出现的时候用{@link}标签(45)

文档注释中的每个包、类、接口、方法和字段的名字都可以通过使用编码得当的标签{@link}替换,从而将其转换成超文本连接。

/**

*应用Flag对象来表示value参数。

*应用这种形式的构造函数可以取代{@link#Flag(String)}

*…

*/

publicFlag(booleanvalue){……}

/**

*如果字符串参数不为null并且等于“true”,

*就可以用Flag对象表示true值。

*应用这种形式的构造函数可以取代{@link#Flag(boolean)}

*/

publicFlag(Strings){……}

没有必要为注释块中出现的每一个标识创建连接。过多的{@link}标签使得注释块过于混乱,同时使得源代码难于阅读和维护。

只有文档和相关元素是读者真正感兴趣或有价值时,才为其创建链接。不要每出现一次标识就为其创建链接。如果一个标识符出现多次,只在其第一次出现时创建链接,其后

-25-

VCI编码规范的实例标识方法遵循规则43。而且,一些类和方法对于熟练的程序员来说很常用,他们并不需要这种连接—同样,这些标识符的标识方法也遵循规则43。

4.15为javadoc标签创建和使用一套固定的顺序(46)

SUN公司推荐采用如下javadoc标签顺序。

?

/**

*Description

*

*@author

*@version

*

*@see

*@since

*@deprecated

*/

考虑在每个类和接口的描述中包含@author和@version标签。

按年代的先后顺序排列多个@auther标签,并将类或接口的创建者的名字放在最前面。?

/**

*Description

*

*@param

*@return

*@exception

*

*@see

*@since

*@deprecated

*/

为每个参数包含一个@param标签。当有多个参数时,按参数的声明的先后顺序排列@param标签。

当方法有除void类型外的任何类型返回值时,创建一个@return标签。

为throws语句中每个检查异常创建一个@exception标签。

为每个不受检查的异常创建一个@exception标签,这样用户可以合理的捕获这些异常。当包含多个异常时,按异常类型的先后顺序排列@exception标签。

-26-在类和接口的描述中在方法的描述中

VCI?

/**

*Description.

*

*@see

*@since

*@deprecated

*/

就文档导航和命名资格而言,按照与当前位置的距离排列多个@see标签。在字段的描述中编码规范按参数的数量的多少来排序每组重载方法,并将参数最少的方法放在最前面。/**

*……

*@see#field

*@see#Constructor()

*@see#Constructor(Type…)

*@see#method()

*@see#method(Type…)

*@seeClass

*@seeClass#field

*@seeClass#Constructor()

*@seeClass#Constructor(Type…)

*@seeClass#method()

*@seeClass#method(Type...)

*@seepackage.Class

*@seepackage.Class#field

*@seepackage.Class#Constructor()

*@seepackage.Class#Constructor(Type…)

*@seepackage.Class#method()

*@seepackage.Class#methoc(Type…)

*@seepackage

*@see<ahref=”URL#label”>label</a>

*@see“String”

*……

*/

4.16叙述使用第三人称形式(47)

-27-

VCI编码规范当描述类、接口和方法的目的和行为时,请用第三人称的代词,如they和it;并应用第三人称的动词形式代码第二人称的动词形式,如用“sets”和“gets”代替“set”和“get”。以下是一些在API文档中经常出现的第三人称动词形式。

adds

allocates

computes

constructs

converts

4.17编写独立的概述(48)

javadoc实用工具使用文档描述的第一个语句或短语,作为注释块后类、接口、方法或字段的概述。概述从注释块的头部开始,结束于第一个空格、制表符、行尾或者javadoc标签。

因为这段文本提供很多实体的概述,所以它必须清楚、简单并简明扼要的描述这些实体。而不要依靠注释块中的其他语句为其提供额外的文本或详尽的细节。

思考下述例子:

/**

*请谨慎应用此功能!

*在此节点应用Foo-Bar算法。

*/

publicvoiddoFooBar(){……}

应用javadoc处理这段代码,会为doFooBar方法产生如下的概述:

请谨慎应用此功能!

重新排序注释块可生成较好的概述语句。

/**

*在此节点中应用Foo-Bar算法。

*请谨慎应用此功能!

*/

publicvoiddoFooBar(){……}

如果实体是一个重载的方法,那么此方法的概述必须与其他形式相同方法的概述不同。/**

*应用Flag对象来表示value参数。

*……

*/

-28-deallocatesdestroysgetsprovidesreadsremovesreturnssetstestswrites

VCIpublicFlag(booleanvalue){……}

/**

*如果字符串参数部位“null”,并且等于“true”

*就可以应用Flg对象来表示true值。

*……

*/

publicFlag(Strings){……}

4.18省略行为或服务概述中的主题(49)

概述中不需要包含主题,因为从描述的上下文中可以确定主题。

下面的描述错误的为主题提供了一个冗余的识别。

/**

*这个方法在此节点中应用Foo-Bar方法。

*/

publicvoiddoFooBar(){……}

/**

*方法doFooBar在此节点中应用Foo-Bar方法。

*/

publicvoiddoFooBar(){……}

以下描述正确的忽略了主题。

/**

*在此节点中应用Foo-Bar算法。

*……

*/

publicvoiddoFooBar(){……}

4.19省略事物描述中的主题和动词(50)编码规范

类、接口或字段的概述表示一个事物,它不需要清楚明晰的主题或动词,作为描述它只需要能够识别一个对象即可。描述中不需要主题,是因为可以从上下文中确定主题。不需要动词是因为描述只是简单的声明主题是某个对象、作为某个对象而存在或者表示某个对象。

下述例子阐述了一个包含不必要主题和动词的描述。

/**

*一个线程组表示一组线程。

*……

*/

publicclassThreadGroup(){……}

-29-

VCI删除主题和动词,从而获得正确形式的概述。

/**

*一组线程。

*……

*/

publicclassThreadGroup(){……}

4.20当提及当前类的实例时用“this”而非“the”(51)编码规范

当描述一个方法的目的或者行为时,应用“this”取代“the”来提及定义方法类的实例对象。

/**

*Returnsa<code>String</code>representingthe

*valueofthe<code>Flag</code>object.

*…….

*/

publicStringtoString(){……}

/**

*Returnsa<code>String</code>representingthe

*valueofthis<code>Flag</code>object

*/

publicStringtoString(){……}

4.21不要为方法或构造函数增加圆括弧,除非你想指定某特殊意义(52)

方法或构造函数的参考不能包含圆括弧,除非将这个参考和其重载的方法或构造函数看成一样,并且你希望以单一形式提及重载的操作。

在表示方法的名字时,不要在名字后增加一对空的圆括弧。因为在这个名字存在重载方法,并且重载方法中含有不带参数的方法时,这种表示会造成混乱。

考虑下述所示中定义在类java.lang.String中的重载方法对。

publicclassString{

……

publicStringtoLowerCase(){……}

publicStringtoLowerCase(Localelocale){……}

……

}

如果应用标识符”toLowercase()”来指任何或所有的toLowercase()方法,阅读你文档的人会被弄糊涂。大多数情况下,读者会认为你表述的是第一种形式的方法,而不是你认为的任何一种或者所有。只有你想精确指定某一方法或构造函数时,使用圆括弧。

-30-

VCItoLowerCase

toLowerCase()

toLowerCase(Locale)

注释内容

4.22为每个类、接口、域和方法提供概述(53)指任何一个方法或者所有只指第一种形式的方法只指第二种形式的方法编码规范

应为每个类、接口、域和方法提高一个文档注释,这个注释至少包含描述实体行为概述的一句话。

4.23充分描述每个方法的标记(54)

每个方法的描述应该包含每个参数、每个可检查的异常、每个不能检查相关异常和每个返回值的描述。查看规则46来获取关于javadoc标签顺序和使用方法的信息。

4.24包含示例(55)

解释和理解如何应用软件的一个最简单方式是给出特定例子。

尝试在每个非无效类和方法的描述中包含一个简单例子。应用HTML标签<pre>…</pre>来保持每个例子的格式。

/**

*…

*如果你想格式化多个数字,只获得一次格式是非常高效的。

*这样系统就不需要多次获取本地语言和国家习俗信息。

*<pre>

*

*

*

*}DateFormatdf=DateFormat.getDateInstance();for(inti=0;i<a.length;i++){output.println(df.format(myDate[i])+“;“);

*</pre>

*为不同的地方格式化数字时,在调用方法getDateInstance

*时指定当前地点。

*<pre>

*

*DateFormatdf;df=DateFormat.getDateInstance(Local.US);

*</pre>

*...

*/

publicabstractclassDateFormatextendsFormat{...}

4.25为前置、后置和不变条件编写文档(56)

前置条件是在方法运行之前必须保持为真的条件,确保方法能够正确运行。典型的前

-31-

VCI置条件会限制方法实参的可接受取值范围。编码规范

后置条件是在方法结束后必须保持为真的条件,确保方法能够正确运行。典型的后置条件是从方法的启动得到的对象状态,其中的方法是为了确定初始状态和启动参数。不变条件对于对象来说始终保持为真的条件。一个典型的不变条件是将整形字段vacationDays的值限制在0~25之间。

前置条件、后置条件和不变条件是基于使用类并且和类进行交互的假设之上的。因此为它们书写文档很重要,尤其是这些条件过于占用资源而无法使用运行时断言的时候。

4.26为已知的缺陷和不足编写文档(57)

识别并描述与类或方法相关联的突出问题。标明任何替换方法和迂回工作区。如果有可能,标明问题的解决时间。

尽管没有人愿意公开其代码中存在的问题,但是如果这样做了,你的同事或者客户可能会感激你提供的信息。这些信息会使他们有机会实现迂回的工作区,或者隔离问题,降低日后改动造成的影响。

4.27为同步语义书写文档(58)

方法签名中的synchronized修饰词的存在揭露了是否此方法是否串行化的访问线程来保护对象的状态。用户可以通过阅读javadoc产生的文档来查看方法是否同步。因为javadoc会将修饰词作为synchronized方法签名的一部分。

javadoc也提供第二种同步机制,可以将同步应用在一个代码段中而不是整个方法上。事实上,应用第二种同步机制的方法可能是线程安全的,但是这些方法的签名并没有明确指出这点。在这种情况下,你必须在每个方法的文档中明确指出内部同步方法。内部注释

4.28仅添加能够帮助理解你代码的内部注释(59)

避免插入无用或不相关的文档注释。

publicintoccurencesOf(Objectitem){

//Thisturnedouttobemuchsimpler

//thanIexpected.Let’sGoMets!!

return(find(item)!=null)?1:0;

}

仅加入能够帮助他人理解你代码如何工作的文档注释。

publicintoccurencesOf(Objectitem){

//Thisworksbecausenoduplicatesareallowed:

return(find(item)!=null)?1:0;

}

如果内部注释没有任何价值,那就让代码自己说话。

-32-

VCI4.29描述代码为什么这么做,而不是在做什么(60)

好的代码是自我注释的。其他程序员能够通过这些优秀的代码了解其意图。例如,从下述代码可以知道:当支出超过1000美元时就有5%的折扣。

if(this.invoiceTotal>1000.0){

this.invoiceTotal=this.invoiceTotal*0.95;

}

下述代码给出少许额外信息。

//所有支出超过1000美元都有5%的折扣

if(this.invoiceTotal>1000.0){

this.invoiceTotal=this.invoiceTotal*0.95;

}

读完这些代码后,逻辑严谨的程序员还想知道:

为什么是5%的折扣率。

谁决定了折扣率和现金总数。

何时或者为何这些数量会发生变化。

确定并解释任何特定领域与理解代码相关的知识。

//在金星、木星和地球上这个算式是正确的。

sigma+=(c1*Angle.sin(a1)

+c2*Angle.sin(Angle.minus(L1,F))

+c3*Angle.sin(a2));

4.30避免使用行尾注释(61)编码规范

应该慎重使用附加在工作代码行后面的单行代码或行尾注释,它们通常会影响代码的可视化结构。修改带有行注释的代码,会使得注释被向右移动很多,以至于只能使用换行或者水平滚动才能看到注释。很多程序员通过左侧对齐注释来改善行尾注释的外观,但是每次修改代码时,都需要调整注释使其对齐。这是很浪费时间的。

将单行注释放在单独的一行,紧接着是它解释的代码。这个规则的唯一例外,即当局部变量声明的描述足够短的时候,用行尾注释可以描述清楚并且不会产生超长的代码。

4.31用行尾注释解释局部变量声明(62)

如果局部变量的描述很短,可以考虑将声明和描述放在同一行中。

intcur=0;//Indexofcurrentpatternelement

intprev=0;//Indexofpreviouspatternelement

不要费心调整注释的位置以使其与其他尾行注释对齐。

4.32创建并使用一组关键字来标明尚未解决的问题(63)

为创建特殊注释建立一组关键字,可以应用它们来标明尚未解决的问题,这些问题在代码最终完成时必须完全解决。这些描述应该包含时间和最初提出问题的名字。选择关键

-33-

VCI编码规范字的时候要尽量减少代码的其他地方重复出现这些词。如下代码中,词语”UNRESOLVERD”被一组冒号修饰着来增加其唯一的可能性。

//:UNRESOLVED:EBW,11July1999

//在输入溢出内部缓存时,仍然不能解决这种情况。

while(everMoreInput){

}

4.33在嵌套程度高的控制结构中标记出嵌套结束位置(64)

通常情况下,应该避免使用嵌套较深的控制结构。可以通过在嵌套结尾大括弧的后面加入尾行注释来改善此类代码的可读性。

for(i….){

for(j….){

while(…){

if(…){

switch(…){

}//endswitch

}//endif

}//endwhile

}//endforj

}//endfori

4.34如果两个case标记之间没有break语句,则在它们之间加入“fall-through”注释

(65)

如果switch语句中的case标签中不包含break,则应用“fall-through”来连接下一个标签,同时书写注释来表明你的意图。其他程序员要么会错误的猜想break的位置,要么认为你的忘记书写了。

switch(command){

caseFAST_FORWARD:

isFastForward=true;

//Fallthrough

casePLAY:

caseFORWARD:

isForward=true;

break;

caseFAST_REWIND:

isFastRewind=true;

-34-

VCI//Fallthrough

caseREWIND:

isRewind=true;

break;

….

}

注意:两个相邻的标签不需要干预的注释。

4.35标记空语句(66)编码规范

当一个控制结构含有设计好的空语句时,如while语句或for循环语句,请书写注释来表明你的意图。

5编程约定

5.1将表示基础数据类型的类声明为final(67)

简单类表示基础数据,例如工程包中的类ComplexNumber,在其目标领域中被广泛应用。这样情况下,效率就变成一个重要的问题。将类定义为final,其中的方法会被高效的访问。

当然,把类声明为final就会禁止其作为超类使用。然而,很少扩展一个实施基础数据类。在大多数情况下,对象组合是更适合的重用机制。

5.2通过本地类型和其他的具体类型来创建具体类型(68)

每个具体类型接口里的非本体化、非具体类型都会引入一种新的、潜在的、不稳定的依赖关系,这样会使具体类型的每一个客户易于受其他类型的不稳定因素影响。

将具体类与非本地和非具体类型的依赖关系降至最低。纯粹由本地类型定义的具体类与由其他具体类定义的具体类相比,具有更好的独立性和稳定性。这一点对于实现基础数据类型的类尤为重要,因为这些底层类的关联关系会扩散到整个应用中。考虑java.util.BitSet类的公有接口:

publicfinalclassBitSet…{

publicBitSet(){…}

publicBitSet(int){…}

publicvoidset(int){…}

publicvoidclear(int){…}

publicbooleanget(int){…}

publicvoidadd(BitSet){…}

publicvoidor(BitSet){…}

publicvoidxor(BitSet){…}

publicinthasCode(){…}

-35-

VCIpublicintsize(){…}

publicbooleanequals(Object){…}

publicObjectclone(){…}

publicStringtoString(){…}

}编码规范

这个类中应用五种数据类型:自我引用的BitSet类型,基础类型的int和boolean以及java本地类型Object和String。因为BitSet接口应用稳定的本地java类型,所以其他类外的修改几乎不会影响到类或类的客户。

5.3定义小的类和方法(69)

较小的类和方法比较容易设计、编码、测试、编写文档、阅读、理解和使用。因为较小的类通常含义较少的方和且代表比较简单的概念,所起其接口能够表现出较好的内聚性。将每个类的接口的数量限制在方法能够提供必要功能的最小限度内。如果当一般形式能够满足要求时,就不要试图增加方法的“便利”形式。

有各种各样非正规的变成指南来指导人们如何构建臃肿的类和方法—这需要你自己来判断。如果一个类或方法看起来太大,那就考虑将此类或方法重构为其他的类和方法。

5.4定义子类,以便能够使用超类的地方都可以使用子类(70)

子类通过重载来改变或限制祖先类的行为,它是类的一种特殊化。子类实例与其祖先类的实例相比,其替换性是有限的。这些特殊化并非所有父类可以使用的地方都可以使用。在行为上与其祖先类相兼容的子类是一种子类型,它和他祖先的实例是可以互换的。实现子类的子类型不会重载祖先类的任何东西,它仅仅是扩展了祖先类的服务。子类和超类具有相同的属性和关联。

以下设计原则强调了可替代性的问题:

里氏替代原则:

使用基类引用的方法必须能够使用子类的队形,而不必知道其自身。

根据这一原则,派生类队形替换父类队形的能力是良好设计的一大特征。这样的设计能够提供更好的稳定性和可靠性。遵循这一原则设计表明设计者很好的定义了基础的抽象,并使接口通用化。

任何需要修改代码来处理引入新派生类的设计,都是失败的设计。无论何时派生类违反了父类和客户之间确定的约定,必然会强制对现有代码的更改。当一个方法接受了父类的实例,却使用派生类型的实例来控制其行为,那么为了引入派生类也一定做修改。此类修改违背了“开放-封闭原则”,应该尽量避免。

开放-封闭原则

软件实体(类、模型、函数等)对扩展开放,对修改封闭。

请看下面代码:

classShape{

-36-

VCI…

publicShapegetNext(){returnthis.next;}publicintgetDepth(){returnthis.depth;}…

}

classCircleextendsShape{…}

classRectangleextendsShape{…}

classCanvas{

publicvoiddrawShapes(ShapeListlist){Shapeshape=list.getNextShape();

//Usenulltodectectendoflist

while(shape!=null){

drawShape(shape);

shape=list.getNextShape();

}

}

publicvoiddrawShape(Shapeshape){//使用派生类型来调用相关方法

if(shapeinstanceofCircle){

drawCircle((Circle)shape);

}elseif(shapeinstanceofRectangle){drawRectangle((Rectangle)shape);

}

}

publicvoiddrawCircle(Circlecircle){…}

publicvoiddrawRectangle(Rectanglecircle){...}}

classShapeList{

-37-编码规范

VCI…

protectedShapefirst;

protectedintentries;

publicintgetEntries(){this.entries;}编码规范

publicShapegetNextShape(){

Shapetemp=this.first;

if(null!=this.first){

this.first=temp.getNext();

this.entries--;

}

//当空时返回null

returntemp;

}

}

这些类组成了一个简单的会图包,Shape存储在ShapeList中,然后传递给Canvas处理。Canvas对象中的drawShapes方法一次从列表中读取一个Shape对象,分配给合适的绘制方法中。继续这样的处理,直到getNextShape方法返回空值,表面列表已经被完全遍历。

现在,假设我们的设计调用一个DepthFilterShapeList类,可以过滤任何深度值落在一个特定目标范围之外的所有Shape对象。

classDepthFilteredShapeListextendsShapeList{

protectedintmin;

protectedintmax;

publicShapegetNextShape(){

Shapetemp=this.first;

if(null!=this.first){

this.first=temp.next;

this.entries--;

intdepth=temp.getDepth();

//Shape在范围内吗?

-38-

VCIif(this.min>depth||depth>this.max){

//No!——返回null。

temp=null;

}

}

//过滤后返回null!

returntemp;

}

}编码规范

然而,这个实现过程存在一个问题。当到达类表的结尾时,getNextShape方法不仅仅返回一个空值,同时为每个过滤的Shape对象返回一个空值。Canvas类并不希望ShapeList有这种行为,当其尝试读取一个Shape对象进行过滤时,会错误的停止处理。这个例子违反了里氏替代原则。

在这种情况下,可以通过修改方法getNextShape使它继续遍历Shape列表,直至找到一个没有被过滤的Shape或者到达列表的末尾,来满足里氏替代原则的要求。

里氏替代原则同样被使用于方法。为识别父类特殊派生类的方法,可能不知道如何处理一个新的派生类。Canvas类中的drawShape方法阐明了这个问题。这个方法询问每个进入的shape来决定其类型,并将其分派给合适的绘图程序。当开发者每次想增加一个Shape的子类时,他必须更改Canvas类中的drawShape方法。

此问题的解决方法是:通过在Shape子类中增加一个drawSelf方法,并应用一组基础的绘制方法替换canvas类中的Shape相关方法,以便shape可以绘制其本身。Shape的每一个子类重载drawSelf方法,调用必要的canvas绘制方法,来生成特定的图形。canvas的drawShapes方法将不再调用drawShape方法来为canvas程序分派图形,取而代之调用每个Shape子类本身的drawSelf方法。

classShape{

publicabstractvoiddrawSelf(Canvascanvas);

}

classCircleextendsShape{

publicvoiddrawSelf(Canvscanvas){…}

-39-

VCI}

classCanvas{

publicvoiddrawShapes(ShapeListlist){

Shapeshape=list.getNextShape();

//使用null来检查列尾

while(shape!=null){

//告诉图形绘制自己

shape.drawSelf(this);

shape=list.getNextShape()p;

}

}

//定义shape会用到的操作方法

publicvoiddrawLine(intx1,inty1,intx2,inty2){

...

}

publicvoiddrawCircle(intx,inty,intradius){

...

}

}

5.5将所有字段私有化(71)

眼不见,心不烦。---匿名编码规范

这样可以保证成员数据的一致性,因为只有拥有他们的类才可以修改它们。通过对象的方法访问所有的成员数据。这样可使对象间的联系最小化,增强程序的可维护性。

5.6使用多态来代替instanceof(72)

不要应用instanceof去选择依赖于对象的行为。这就迫使每次在选择对象类型组发生变化时,修改选择代码。这样会导致代码损坏。

取而代之,可以再从基类继承的方法中实现具体对象的行为。这样可以使用户与基类的抽象想结合,而不需要知道其派生类。引入新的类时不用考虑用户是否知道。类型安全

5.7以java.lang.Object包装通用类,提供静态类型检查(73)

-40-

VCI编码规范通过包装通用类型来保证类型安全,这个通用类型将Object类型和强制转换为特定类型的对象相交换。下述代码展现了如何将通用类型队列转化为特定类型队列。publicclassQueue{

publicvoidenqueue(Objectobject){…}

publicObjectdequeue(){...}

}

publicclassOrderQueue{

privateQueuequeue;

publicOrderQueue(){

this.queue=newQueue();

}

publicvoidenqueue(Orderorder){

this.queueu.enqueue(order)

}

publicOrderdequeue(){

return(Order)this.queue.dequeue();

}

}

5.8以类的形式封装枚举类型(74)

以类的形式封装枚举类型,提供枚举成员安全类型比较。

publicclassColor{

privatestaticintcount=0;

publicstaticfinalColorRED=newColor(count++);

publicstaticfinalColorGREEN=newColor(count++);

publicstaticfinalColorBLUE=newColor(count++);

publicintvalue;

pirvateColor(intvalue){

this.value=value;

}

-41-

VCIpublicbooleanequals(Colorother){

returnthis.value==other.value;

}

publicstaticintColor.count(){

returncount;

}

}

ColoraColor=Color.RED;

if(anotherColor.equals(aColor)){

}

语句与表达式

5.9应用等价的方法替代重复、复杂的表达式(75)编码规范

编写代码力求一步到位。提取出共用的功能,将其重新封装类或者方法。这样使得代码易于学习和理解。修改尽量本地化,维护更方法,测试的工作量也会减少。

5.10使用块语句代替控制流结构中的表达式(76)

java块语句提供一种机制,即将任意多的语句当做一个符合语句来处理。块语句能够应用在任何常规语句能够应用的地方,包括java控制结构中的表达式语句主体。

尽管语言本身可以使你应用简单、非块语句作为这些结构的主体,但你还应该使用块语句。

块语句减少了控制语句嵌套时经常引起的混淆,同时提供改善代码可读性的组织机制。下述代码让人觉得迷惑,因为缩进让人误以为else语句是与第一个if语句相关联。而编辑器则将其与对二个语句对应处理。Java语句规范将这种现象称为“摇摆else问题”(danglingelseproblem)。使用块语句可以消除这个问题。

if(x>=0)

if(x>0)positiveX();

else//Oopse!实际上与最近的if匹配

negativeX();

if(x>=0){

if(x>0)positiveX();

}else{

-42-

VCInegativeX();//这才是我们想要的。

}编码规范

在下述的例子中,上面的代码要比下面得代码难于修改。这是因为你不能在不改变现有代码结构的前提下增加其他代码,而下面的代码已经使用的块语句,很容易进行修改:for(inti=n;i>=0;i--)

for(intj=n;j>=0;j--)

f(i,j);

//g(i,j)不能在此增加!

for(inti=n;i>=0;i--){

for(intj=n;j>=0;j--){

f(i,j);

g(i,j);//可以在此增加!

}

}

如果控制语句的主体是一个单独并且不重要的语句,可以将整个语句放在一行,但必须能够增强可读性。这种情况只是例外,而不是通常的做法。

5.11使用括号明确操作顺序(77)

算数表达式中的操作顺序常常并不明显。即使你自己很清楚这个顺序,但别人确未必知道。

//无关却有用的圆括弧

intwidth=((buffer*offset)/pixelWidth)+gap;

5.12在switch最后一个case语句中使用break语句(78)

编写下述switch语句代码的人认为,在Y情况之后再也没有其他语句,所以不需要break语句。

switch(…){

casex:

break;

caseY:

}

如果需要加入一种新的case语句,而执行加入的人只是简单的将此case语句加入在最后一个case语句的后面,而没有看到最后一个case语句没有break语句,这该怎么办

-43-

VCI呢?结果就不经意的引入了一个很难察觉的“贯通”错误,如下所示:switch(…){

caseX:

break;

caseY:

…//Oops!不想要的贯通

caseZ:

….

}编码规范

以防此类问题发生,在switch语句最后一个case语句中都要加入break语句,即使是default情况也不例外。

switch(…){

caseX:

break;

caseY:

break;//OK!再也没有贯通!

caseZ:

….

beak;

default:

…//抱怨值!

break;

}

在真的发生“贯通”的语句中,不要忘记加入“贯通”的注释。

5.13使用equals(),而不是==来检测对象的对等关系(79)

许多C++程序员在处理java的日期和字符串数据类型时会犯这些错误:Datetoday=newDate();

while(date!=today){

}

Stringname;

-44-

VCI…

if(name==“Bob”){

hiBob();

}编码规范

在Java中,“!=”和“==”是用来比较对象的身份,而不是对象的值。你必须应用equals方法来比较实际的字符串。

注意,与表达式name.equals(“Bob”)不同,表达式”Bob”.equals(name)在name为null时不会抛出异常。

构造

5.14构造状态有效的对象(80)

不要构造无效对象。如果对象必须在无效的状态下构造,之后必须进行进一步的初始化才能使其变得有效,那么就使用一个与多级构造相协调的静态方法。构造方法应该构造一个对象,从而在方法完成时,新的对象处于有效状态。通过将构造函数设置为protecdted或者private来隐藏所有不能构造有效实例的构造。

5.15不要在构造函数中调用一个非final的方法(81)

子类可能会重载非final的方法,Java会根据实际的构造对象类型来访问此方法—在执行派生类构造函数之前。即当构造调用派生类方法时,派生类可能处于非有效状态。为了避免这种情况发生,在构造函数中只访问final方法。

5.16用嵌套的构造函数来消除冗余(82)

为了避免书写冗余的构造函数代码,从高级的构造函数中调用低级的构造函数。下述代码在两个不同的地方实现相同的低级的初始化。

classAccount{

Stringname;

doublebalance;

finalstaticdoubleDEFAULT_BALANCE=0.0d;

Acount(Stringname,doublebalance){

this.name=name;

this.balance=balance;

}

Acount(Stringname){

this.name=name;

this.balance=balance;

-45-

VCI}

}

以下代码只在一处实现了低级的初始化。

classAccount{

Stringname;

doublebalance;

finalstaticdoubleDEFAULT_BALANCE=0.0d;

Acount(Stringname,doublebalance){

this.name=name;

this.balance=balance;

}

Acount(Stringname){

this(name,DEFAULT_VALUE);

}

}编码规范

这种方法对于使用断言同样有帮助。这明显减少了特定构造函数中参数出现的次数,从而减少了参数有效性检验的次数。

异常处理

5.17应用不受检查、运行时异常来报告可能发生在程序逻辑中出错的严重未查明的错误

(83)

捕获并处理运行时异常是有可能的,然而,它们极有可能导致程序的终止。抛出运行时异常一般是由于编程的错误造成,例如断言错误、使用溢出的索引、除数为0或者引用一个空指针。

5.18应用检查异常来报告可能发生、而在正常情况下很少发生的错误(84)

检查异常表示存在一个在正常条件下不会发生的严重问题。调用函数必须捕获这些异常。根据特定应用,程序或许能从一个检查异常中恢复。也就是说,它并不表示程序逻辑中的基础性错误。

5.19应用返回代码报告可预知的状态变化(85)

对于可预知的状态变化,应用返回值、标记或特定方法返回状态值。这样可以增加代码的可读性及流程的简单明了。例如,在读取文件的过程中,希望在某一特定点到达文件的结尾。

5.20仅转换异常来添加信息(86)

-46-

VCI保留所有异常信息,不要丢弃低级别的解释:

try{

for(inti=v.size();--I>=0;){

ostream.println(v.elementAt(i));

}

}catch(ArrayOutOfBoundse){

//永远不会到达这里

thrownewUnexpectedExceptionError(e);

}

5.21不要私自处理运行时或错误异常(87)

不遵守这条规则经使得代码由于信息都是二难于调试。

try{

for(inti=v.size();--I>=0;){

ostream.println(v.elementAt(i));

}

}catch(ArrayOutOfBoundse){

//Oops!我们永远不会到达这里…

//…但是如果我们这样做了,也不会有人知道!

}编码规范

即使你已经编写一段捕获代码块来捕获你不希望发生的异常,至少将“stacktrace”打印出来。你永远也不会知道,在你的软件中不可能事情什么时间发生。try{

for(inti=v.size();--I>=0;){

ostream.println(v.elementAt(i));

}

}catch(ArrayOutOfBoundse){

//Oops!永远不会到达这里…

//但是如果发生了则打印一条“stacktrace”…

e.printStackTrace();

}

5.22应用finally块来释放资源(88)

一旦进入一个try块语句,保证所有对应的finally块语句能够运行。这为finally块释放资源提供了一个良好的场所,这些资源是优先进入或在try块语句内的。

在第一个例子中,如果异常或者返回发生在创建输出流之后,函数将在不关闭也不清空流的情况下关闭。

-47-

VCIpublicvoidlogSomeStuff(){

OutputStreamlog=newFileOutputStream(“log”);

//可在此获得异常

log.close();

}编码规范

在下面的例子中,我们应用一个finally块语句在执行线程退出try块后保证流始终会关闭。即使抛出异常或者执行返回语句,线程退出代码块,这依然有效。OutputStreamlog=null;

try{

log=newFileOutputStream(“log”);

}finally{

if(log!=null){

log.close();

}

}

断言

5.23按照约定编程(89)

考虑每个方法调用者和被调用者之间的约定。这个约定声明,调用者必须遵守方法及其前置条件,并且必须返回符合方法后置条件的结果。

遵守方法前置条件通常是指传递方法所期望的参数,也可能意味着按正确的顺序调用一系列的方法。遵守方法的后置条件,方法必须正确完成调用其所要完成的工作,还必须以一致的状态保留对象。

使用断言检查任何适当的公有方法的前置条件和后置条件(参考规则92)。在方法的开始所有代码没有执行时检查前置条件,在方法的结尾处传递返回值前检查后置条件。继承类中覆盖基类方法的方法必须保持基类方法的前置和后置条件。为了确保这一点,应用模板方法设计模式。

将每个公用方法定义为finally类型,并创建一个平行的非final型受保护方法来实现函数体。公有final方法首先测试前置条件,然后调用相关联的受保护方法,最后测试后置条件。派生类可能通过覆盖父类与每个公有final方法相联系的非final受保护方法来覆盖公用行为。

classLinkedList{

publicfinalsynchronizedvoidprpend(Objectobject){

-48-

VCI编码规范

//测试前置条件

if(Assert.ENABLED){

Assert.isTrue(object!=null);

}

doPrepend(object);

//测试后置条件

if(Assert.ENABLED){

Assert.isTrue(first()==object);

}

}

protectedvoiddoPrepend(Objectobject){

Nodenode=newNode(object);

if(this.head==null){

this.head=node;

}else{

node.next=this.head;

this.head=node;

}

}

}

这个技术同样可以用在保证方法是否保持同步,即使是在覆盖的情况下。派生类可能通过应用非同步的版本覆盖基类的同步方法,从而覆盖基类的同步语义-派生类方法没有继承synchronized限定词。超类可以通过提供一个公有的final同步方法类调用非final方法,来保证同步。

5.24应用无用代码消除机制来实现断言(90)

断言是一种表达式,在代码正确运行时,作为程序员的你始终保证表达式为真。代码中的断言要确保基本编码假设没有被违背。如果断言的评价为假,则代码一定有缺陷。使用断言来测试整个代码建立的基础前提是否成立。断言需要耗费运行时间,所以我们通常想在发布的代码中移除断言。为了做到这一点,我们应用无用代码消除机制。当Java编译器要消除无用的代码时,使用无用代码消除机制。例如,当编译器编译如下代码时,它知道变量FALSE的值总为false,因为FALSE是静态final变量。这就允许编译器消除if表达式后面的代码块,因为编译器知道它的值永远不会为true。classDeadCode{

-49-

VCIstaticfinalbooleanFALSE=false;

publicvoidexample(){

if(FALSE){

System.out.println(“Nevertobeseen.”);

}

}

}编码规范

应用我们知道的无用代码消除机制来编写一个断言类,让我们选择什么时候在编译生成的代码中包含断言。

publicclassAssert{

publicstaticfinalbooleanENABLED=true;

publicstaticfinalvoidisTrue(booleanassertion){

if(Assert.ENABLED&&!assertion){

thrownewRuntimeException(“AssertionFailed”);

}

}

if(Assert.ENABLED){

Assert.isTrue(a>b);

}

}

要关闭断言,只需在断言类中将变量ENABLED设置为false即可。

失败的断言表明程序的逻辑中有错误,要么在方法的使用中,要么在方法的实现上。因此,通过抛出未检查异常如RuntimeException或者由此引起的异常来报告断言失败。

5.25应用断言来捕获代码中的逻辑错误(91)

断言是一个布尔表达式,在程序正确操作时始终保持为真。应用断言来使程序所做的假设有效。

5.26应用断言来检测方法的前置和后置条件(92)

方法的前置条件是方法合理运行所必需的条件。例如,前置条件可以检测传递给方法的参数是否合理或者检测对象是否处于有效状态。

后置条件断言在方法完成后执行,它验证对象是否依旧处于有效状态以及方法的返回值是否合理。

并发

并发存在于当两个或两个以上线程同时执行指令的时候。单处理器系统通过交换两个

-50-

VCI编码规范或两个以上的线程操作来支持并发。多处理器系统通过在每个处理器上执行一个线程来支持平行并发。当类通过创建额外的线程来完成其任务时,那么这个类是multithread-hot,或者称为MT-hot。

很多应用通过应用并发来实现是大有好处的。在执行的并发模型中,一个应用被分为两个或多个进程或线程,每个按其自己的语句顺序或指令顺序执行。一个应用可能用一个或多个进程组成,而一个进程又可能由一个或多个线程组成。执行操作可能被分发给网络中的两台或多台机器,或者一台机器的两个或多个处理器,或者在一个处理器上交错执行。通常,独立执行的进程或线程必须竞争访问共享资源和数据,并且必须相互合作来完成总体任务。

并行应用程序的开发是一项复杂的任务。设计一个并行应用程序包括确定必要进程或线程的数目、它们的特定职能,以及与其交互的方法。它还包括确定良好的、合法或不变的以及不好的或者非法的编程状态。最关键的问题是查找并实现一个解决方法,维持或保证良好的编程状态,而避免不好的编程状态,即使是在两个或多个线程可能处理统一资源的情况下。

在并行环境下,程序员通过限制或协商访问同步的共享资源,来维持设想的程序状态。同步的原则是,阻止在同时执行指令序列中出现的不希望发生地或未预料的干扰。

5.27仅在适当的地方使用线程(93)

线程并不是改善应用程序性能的“银弹”。如果应用不适合多线程,那么按照多线程的指导开发,则会因为多线程之间的过多的转换需求而使得应用变慢。

在为你的应用程序引入线程之前,确定是否可以从其应用中受益。仅在必要的时候使用线程。

?

?

?同时对多事件做出反应。提供很高的响应速度利用多处理器计算机的优势例如:因特网浏览器或服务器。例如:一个即使在进行其他计算的同时,仍能连续响应用户操作的用户界面实现。

例如:一个面向特定计算机架构的应用程序。

同步

同步,指的是防止并发线程之间意外的交叉操作或干扰而设计的一套机制或线程。程序员可以选在以下两种同步方法中的一种:互斥算法或者条件同步算法。

互斥算法是将细密的原子动作并入到粗糙的动作中,并使组合体也是原子操作。条件同步算法指的是一个过程或机制,它延迟线程执行直到线程满足弄些假设或条件。线程不再执行,因为它被延迟了,或者等待的某种同步机制被阻塞了。一旦机制畅通、被唤醒或者被通知,线程能够运行并且符合进一步运行的条件。

-51-

VCI编码规范线程同步有两个最基本的用途:保证共享数据的弯成型和高效的在相互协作线程间传递程序状态的变化。

Java通过Object类提供的机制,同时支持互斥算法和条件同步算法。

5.28避免同步(94)

同时是非常耗资源的。需要花费时间来获取和释放同步某段代码所必须得同步对象。而且,同步序列化访问对象,将并发降至最小化。在同步前认真考虑,只在真正必要的时候使用同步。

不要随意同步所有的公有方法。在同步一个方法之前考虑,它是否访问共享的非同步的状态。如果答案是否定的—如果方法只操作其本地的变量、参数或者同步对象—这时是不需要同步的。

不要同步提供基础数据类型或结构的类。让对象的用户决定同步是否必要。通常在单独锁定对象的权限范围内,用户在外部同步对象。

5.29应用同步包装器来提供同步接口(95)

应用同步包装器来提高同步形式的类。同步包装器提供与原有类相同的接口,但是它的方法是同步的。包装器类中的静态方法能够访问同步包装器。下面的例子讲述了一个栈,这个栈有一个默认非同步的接口和一个包装器类提供的接口。

publicclassStack{

publicvoidpush(Objecto){…}

publicObjectpop(){…}

publicstaticStackcreateSynchronizedStack(){

returnnewSynchronziedStack();

}

}

classSynchronizedStackextendsStack{

publicsynchronizedvoidpush(Objecto){

super.push(o);

}

publicsynchronizedObjectpop(){

returnsuper.pop();

}

}

5.30如果方法中包含不需要同步的重要操作,那么不要同步整个方法(96)为了使程序中的并发最大化,必须最小化锁定所获得的频率和时长。进入

-52-

VCI编码规范synchronized方法或语句的线程试图获取一个锁定。在同一时间内,只要一个县城可以获锁的使用权,所以锁定可以被用来串行化的访问代码或者程序状态。当线程完成在同步代码段的执行之后释放锁定,从而其他线程可以尝试获取锁定的使用权。

以synchronized关键字注释的方法,在方法的开始时获得其相关联对象的锁定,并保持拥有锁定至方法的结束。通常情况下是这样,然而方法中仅有少数操作可能请求同步。这种情况下,方法级同步是很不合适的。

方法级同步的替代方案是使用同步块语句。

protectedvoidprocessRequest(){

Requestrequest=getNextRequest();

RequestIdid=request.getId();

synchronize(this){

RequestHandlerhandler=this.handlerMap.get(id);

}

handler.handler(request);

}

5.31读写实例变量时避免不必要的同步(97)

Java语句保证对象引用和所有的原始类型的读写操作是原子的,除了long类型和double类型。然而,我们可以再读写原子数据是避免同步。尽管如此,还是要小心,如果原子变量的值依赖于其他变量或者与其他变量相关联,这时同步就是必要的。在下面的例子中,x和y的赋值必须是同步的,因为他们的值是相互依赖的。publicvoidsynchronizedsetCenter(intx,inty){

this.x=x;

this.y=y;

}

下面的例子不需要同步,因为它使用了一个对象引用的原子操作。

publicvoidsetCenter(Pointp){

this.point=(Point)p.clone();

}

5.32使用notify()而不是notifyAll()(98)

java.lang.Object中方法notify()唤醒一个单独线程等待某一条件,而方法notifyAll()则唤醒所有的线程等待该条件。如果可能,使用方法notify()而不是notifyAll(),因为前者更高效。

当线程等待某个单独的条件,并且在某一时刻只有一个等待线程时,使用notify()方法。例如,如果notify()给出信号表明一个项目应经被写入到队列中,那么只要一个线程能够从队列中读取对象。这种情况下,唤醒多个线程是浪费的。

-53-

VCI编码规范当线程等待多个条件,或者有多个线程响应某个信号时,使用方法notifyAll()。

5.33为同步初始化使用双重检查模式(99)

在需要使用同步的情况下,在初始化的过程中而不是之后使用双重检查模式。

在下面代码中,只有实例变量log为null时才需要初始化。为了防止两个线程同时初始化字段,函数getLog()声明为同步。

synchronizedLoggetLog(){

if(this.log==null){

this.log=newLog();

}

returnthis.log;

}

这段代码也能防止两个线程同时初始化,但是它使用了双重检查模式来避免除初始化外的同步。

LoggetLog(){

if(this.log==null){

synchronized(this){

if(this.log==null){

this.log=newLog();

}

}

}

returnthis.log;

}

效率

5.34使用懒惰初始化(100)

除非需要,请不要创建对象。如果某个对象在程序的正常执行过程中不需要,那么在需要的时候再创建此对象。

应用辅助方法来获取对象的访问。对象的所有用户,包括在同一个类中,必须通过辅助方法来获得对象的引用。

classPersonalFinance{

LoanRateCalculatorloanCalculator=null;

LoanRateCalculatorgetLoanCalculator(){

if(this.loanCalculator==null){

this.loanCalculator=newLoanRateCalculator();

-54-

VCIreturnthis.loanCalculator;

}

}

}

5.35避免创建不必要的对象(101)编码规范

如果一个新对象的生命周期很短或者被创建后从未被引用,这个规格尤为重要。这不仅浪费执行时间来创建对象,而且同样浪费时间进行垃圾回收。

如下述代码所示,冗余的初始化很常见,也很浪费资源。

ColorgetTextColor(){

Colorc=newColor(…);

if(this.state<2){

c=newColor(…);

}

returnc;

}

如果不知道自己需要什么,请不要创建对象。

5.36重新初始化并重复使用对象来避免创建新对象(102)

缓存并重用频繁被创建并生命周期短暂的对象。

应用附属方法来而不是构造函数来重新初始化对象。

仔细选择一个不需要创建自己对象的实现来管理被缓存的对象。这可能达不到我们的目的。

应用工厂实现来封装缓存和重用对象的机制。为合理的管理这些机制,必须将从对象工厂中获得的对象返回给同一工厂。这意味着对象和其工厂之间的联系必须保持在如下的某个地方。

?在类中—一个独立的静态工厂与对象的类相联系,并且这个工厂管理着类中所有的对象。

?在对象中—对象维持着对管理工厂的引用。

?在对象所有者中—对象的所有者维持着来自对象获得的工厂的引用。

5.37把优化工作放到最后(103)

优化的第一原则是:

不要优化。

优化的第二准则是(仅针对专家):

还是不要优化。

--MichaelJackson,MichaelJacksonSystemsLtd.

除非你确定需要修改代码,否则不要浪费时间来优化代码。

-55-

VCI编码规范请记住80-20原则---系统中20%的代码使用80%的资源(平均来讲)。如果你需要进行优化,确定你修改的是那20%的代码。

6包约定

这一部分包含创建包的指导方针。查看涉及包命名约定的规则15-17。

6.1将经常使用、变化、发布或者相互依赖的类放置在同一包中(104)

这一规则包含几条相关包设计的原则。

全部重用原则

包中所有类被一同重用。如果你重用包中的一个类,那么你就应用了包中所有的类。将你经常一同使用的类和接口放在同一个包内。这些类连接紧密,你不能只应用其中的一个类而不应用其他的类。紧密连接类型的示例包含:

?容器和迭代。

?数据库的表、行和列。

?日历、日期和时间。

?点、线和面。

共同关闭原则

一个包中所有的类应该对同一类变化关闭。一个变化影响了一个包,也就影响了包中所有的类。

将可能在同一时间、因同一原因发生改变的类合并到一个包中。如果两个类关联如此紧密,即改变它们中的一个通常情况下也改变了另一个,则将它们放入同一个包中。重用发布等价原则

重用的单元就是发布的单元。高效重用需要从一个变化控制系统中获取发布的轨迹。这个包是重用和发布的有效单元。

将一个单独类当做是发布的单元是不切实际的。一个典型的应用可能包含成千上万个类,所以,以类-类为基础的发布代码不仅会显著增加集成和测试过程的复杂度,也会显著增加整个软件修改的概率。

包为发布类和接口提供了一个非常便利的机制。包中的每个类和方法可能在发布的代码中存在几个相互独立的版本,但是发布的包只捕获类和接口最新的版本。将包作为发布和发行的主要单元。

无环依赖原则

包之间的依赖结构必须是一个直接无环图,即在依赖结构中没有环。

如果两个包直接或间接相互依赖,你不能不受约束的发布其中的一个而不发布另一个。因为在一个包中的改变会强制另一个包发生改变。这类有环依赖显著降低了系统的稳定性,并且通过将每个包的开发分派给不同的开发人员或小组来减少开发时间的想法化为乌有。通过合并相互依赖的包,或者新建一个包来抽取两个包中相互依赖的部分,逐步的消

-56-

VCI除有环依赖。

6.2将不稳定的类和接口放在单独的包中(105)编码规范

避免将易变的类和接口同稳定的类和接口放在同一个包中。如果你把包作为软件发布和发行的基本单元,在你重新发布整个包时,用户才能获得易变类和方法最新改变的访问权。每次发布包后,尽管很多类没有发生变化,用户必须花费时间和精力去重建和重新测试包中的所有类。

将不稳定的类和稳定的类分离,可减少代码的新发布对原有代码的影响,从而减少对用户代码的影响。

6.3避免让不易于变化的类依赖于易于变化的类(106)

此规则衍生于如下设计原则:

稳定依赖原则

包之间的依赖要以增加稳定性为导向。包应该仅仅依赖于比其更稳定的包。

如果包含不易变化类型的包,依赖于包含易于或可能发生变化类型的包,那么易变包将阻止易变包的变化。

在软件系统中,尤其是分阶段开发的系统中,某些包总会有一定程度上的不稳定。这类系统的开发人员为了实现系统功能,必须能够自由修改和扩展尚未稳定的包,而不需要担心此举会对下游造成不利影响。

不要在包中创建对不稳定包的依赖。如果依赖无可避免,可引入一个新的创建包,由它来转移并承载稳定包和不稳定包之间的依赖关系。

6.4最大化的抽象已达到最大的稳定性(107)

这个规则衍生于如下设计原则:

稳定依赖原则

包的稳定性与其抽象程度成正比。包抽象程度越高,它就越趋于稳定。包越具体,它越趋于不稳定。

应用稳定抽象来创建稳定的包。在抽象的类和接口中捕获高水平、稳定的概念,并用具体类来实现。将抽象的类和接口与具体的类和接口分离,从而形成独立的稳定的和不稳定的包。这就可以保证让不稳定包中的衍生类依赖于稳定包中的抽象基类和方法。

6.5将高层次的设计和架构作为稳定的抽象,组织为稳定的包(108)

要想成功的规划和管理一个软件的开发过程,就必须使高级设计尽快稳定并且一直保持稳定。如果系统架构持续变化,没有那个开发管理者能够指望精确规划、评估确定时间并分配资源。

一旦高级架构的设计完成,就应用包来将稳定的设计部分与易变的实现分离。首先将架构中高级设计抽象组织为包,再将这些抽象的具体实现组织成依赖于高级抽象包的单独包中。

6.6概要

-57-

VCI1、保持原有风格。

2、坚持最少惊讶的原则。

3、第一次就把事情做对。

4、记录所有非规范行为。

5、缩进嵌套代码。

6、拆分长行。

7、包含空白空间。

8、不要应用“难以忍受的”TAB键。

9、使用有意义的名字。

10、

11、

12、

13、

14、

15、

16、

17、

18、

19、

20、

21、

22、

23、

24、

25、

26、

27、

28、

29、

30、

31、

32、

33、

34、使用人们熟悉的名字。慎重使用过长的名字。加入元音字符。大写首字母缩略词的第一个字母。不要使用只通过大小写区分的名称。使用公司域名的倒置小写形式作为包名的权限定词。使用单独小写的单词作为每个包的根名。编码规范仅当新旧版本二进制兼容时,其包名可以使用相同的名字,否则请使用新名字。大写类和接口中每个单词的首字母。用名词命名类。复数化表示成组的属性、静态服务或常量的名字。用名词或者形容词命名接口。在方法命名中小写第一个单词并大写其他单词的首字母。用动词命名方法。遵循JavaBeans的约定来命名访问属性的方法。在变量命名中小写第一个单词并大写其他单词的首字母。应用名词命名变量。采用复数形式命名集合引用。为不重要的临时变量建立并使用一套标准的名字。用“this”限定成员变量来与本地变量区分。在构造函数或“set”方法中将参数赋值给成员变量时,用与成员变量相同的命名常量时,每个单词用大写字母且每两个单词用下划线分隔。为你代码的使用和维护人员书写文档。保持注释和代码同步。应用主动语态,忽略无用的单词。

-58-名称作为参数命名

VCI35、

36、

37、

38、

39、

40、

41、

42、

43、

44、

45、

46、

47、

48、

49、

50、

51、

52、

53、

54、

55、

56、

57、

58、

59、

60、

61、

62、

63、

64、

65、

注释。

66、

67、

68、标记空语句。将表示基础数据类型的类声明为final。通过本地类型和其他的具体类型来创建具体类型。

-59-编码规范应用文档注释来描述编程接口。应用标准注释来隐藏代码而不是删除。应用单行注释来解释实现细节。在编写代码前描述编程接口。为公有、受保护、包和私有的成员建立文档。为每个包提供概述。为包的每个应用程序或组提供概述。对所有的文档注释使用统一格式和组织结构。将关键字、标识符和常量放在<code>……<code>标签中。将代码放入<pre>…</pre>标签中。在标识符第一次出现的时候用{@link}标签。为javadoc标签创建和使用一套固定的顺序。叙述使用第三人称形式。编写独立的概述。省略行为或服务概述中的主题。省略事物描述中的主题和动词。当提及当前类的实例时用“this”而非“the”。不要为方法或构造函数增加圆括弧,除非你想指定某特殊意义。为每个类、接口、域和方法提供概述。充分描述每个方法的标记。包含示例。为前置、后置和不变条件编写文档。为已知的缺陷和不足编写文档。为同步语义书写文档。仅添加能够帮助理解你代码的内部注释。描述代码为什么这么做,而不是在做什么。避免使用行尾注释。用行尾注释解释局部变量声明。创建并使用一组关键字来标明尚未解决的问题。在嵌套程度高的控制结构中标记出嵌套结束位置。如果两个case标记之间没有break语句,则在它们之间加入“fall-through”

VCI69、

70、

71、

72、

73、

74、

75、

76、

77、

78、

79、

80、

81、

82、

83、

错误。

84、

85、

86、

87、

88、

89、

90、

91、

92、

93、

94、

95、

96、

97、

98、

99、应用检查异常来报告可能发生、而在正常情况下很少发生的错误。应用返回代码报告可预知的状态变化。仅转换异常来添加信息。不要私自处理运行时或错误异常。应用finally块来释放资源。按照约定编程。应用无用代码消除机制来实现断言。应用断言来捕获代码中的逻辑错误。应用断言来检测方法的前置和后置条件。仅在适当的地方使用线程。避免同步。应用同步包装器来提供同步接口。如果方法中包含不需要同步的重要操作,那么不要同步整个方法。读写实例变量时避免不必要的同步。使用notify()而不是notifyAll()。为同步初始化使用双重检查模式。定义小的类和方法。定义子类,以便能够使用超类的地方都可以使用子类。将所有字段私有化。使用多态来代替instanceof。以java.lang.Object包装通用类,提供静态类型检查。以类的形式封装枚举类型。应用等价的方法替代重复、复杂的表达式。使用块语句代替控制流结构中的表达式。使用括号明确操作顺序。在switch最后一个case语句中使用break语句。使用equals(),而不是==来检测对象的对等关系。构造状态有效的对象。不要在构造函数中调用一个非final的方法。用嵌套的构造函数来消除冗余。编码规范应用不受检查、运行时异常来报告可能发生在程序逻辑中出错的严重未查明的100、使用懒惰初始化。

101、避免创建不必要的对象。

102、重新初始化并重复使用对象来避免创建新对象。

-60-

VCI103、把优化工作放到最后。

104、将经常使用、变化、发布或者相互依赖的类放置在同一包中。105、将不稳定的类和接口放在单独的包中。

106、避免让不易于变化的类依赖于易于变化的类。

107、最大化的抽象已达到最大的稳定性。

108、将高层次的设计和架构作为稳定的抽象,组织为稳定的包。7参考文献

1、/yfrainy/archive/2008/05/18/2456452.aspx

2、/art/200809/88155.htm编码规范

-61-

更多相关推荐:
Java课程设计心得体会

Java课程设计心得体会

完成Java面向对象程序设计实验课的心得体会

Java面向对象程序设计实验课的心得体会经过这几周对Java面向对象程序设计的学习让我更加了解到Java学习的重要性在实验课上我们完成多个实验在这个阶段的学习中我从认识到熟悉而后到能够自主运用通过对Java的了...

Java心得体会

Java学习心得在学习了近一个学期java后我有了一点自己的见解Java是面向对象的具有平台无关性所以现在被广泛的应用于很多领域也是因为老师在开始上课的时候就给我们讲过这些所以带有兴趣和动力去学习java程序设...

学习Java_的步骤和心得体会(杰瑞教育搜集整理)

学习java的步骤和心得体会很多同学都想要自己学习Java,但是应该如何学习,从何处着手却很迷茫.针对这些同学,烟台杰瑞教育资深Java讲师李老师说,学习Java最终的就是基础知识的学习和框架的掌握,基础知识掌…

java开发实训心得体会

伴随着新年钟声的到来,我不知道我是否是应该高兴还是悲伤。因为伴随自己三个月的华迪实训即将结束。转眼之间三个月的华迪实训就这样在忙碌中过去了。通过此次短暂的java开发习,回顾一下自己这三个月的每一天,觉得过的十…

Java学习心得个人体会

Java学习心得个人体会Java学习路线以下这两张图片很好的规划了Java学习路径你可以另存为图片缩放观看图01传智播客Java学习路线图02疯狂Java学习路线推荐一篇博文JAVA学习路线地址blog4038...

java上机实验心得体会报告

北京联合大学信息学院“面向对象程序设计”课程上机实验报告题目:JAVA上机实验心得体会姓名(学号):专业:计算机科学与技术编制时间:20xx年x月x日版本:1.0.0指导教师:北京联合大学-信息学院编制实验…

Java编程体会

Java编程体会1内部类向上转型为父类的应用内部类向上转型为父类或者接口在程序中就可完全隐藏内部类的实现过程2局部内部类的应用局部内部类定义在外部类的方法中称之为局部内部类局部内部类在外部类中不能直接引用即局部...

java的心得体会

小查教我的做web开发一先从数据库开始先想好算好你需要哪些属性还有类型日期的类型是date然后写好连接好数据库二把你要做的页面在稿纸上先把布局规制好画个草图把大致的框架画出来以及一些功能分配三类设计问题addr...

Java学习心得体会

诚信创新开放合作JAVA的面向对象编程课堂笔记面向对象主要针对面向过程面向过程的基本单元是函数什么是对象EVERYTHINGISOBJECT万物皆对象所有的事物都有两个方面有什么属性用来描述对象能够做什么方法告...

计算机java实训心得体会

计算机java实训心得体会计算机java实训gt心得体会此次只实训了短短的三周虽说时间很短但其中的每一天都使我收获很大受益匪浅它不但极大地加深了我对一些理论知识的理解不仅使我在理论上对Java有了全新的认识在实...

Java学习心得体会

诚信创新开放合作JAVA的面向对象编程课堂笔记面向对象主要针对面向过程面向过程的基本单元是函数什么是对象EVERYTHINGISOBJECT万物皆对象所有的事物都有两个方面有什么属性用来描述对象能够做什么方法告...

java编程心得体会(19篇)