本文介绍的Java规则的说明分为5个级别,级别1是最基本也是最重要的级别,在今后将陆续写出其他的规则。遵守了这些规则可以提高程序的效率、使代码有更好的可读性等。
(1) 避免使用NEW关键字来创建String对象
把一个String常量copy到String 对象中通常是多余、浪费时间的。
Public class test{
Public void method(){
System.out.print (str);
}
private String str = new String ("1"); //这里新建对象是完全没有必要的
private String str2=”2” //正确的应该如此
} |
(2) 避免使用不必要的嵌套
过多的嵌套会使你的代码复杂化,减弱可读性。
Public class test {
String add (){
Int c=(a=a+b)+b; //过于复杂
Return c
}
} |
(3) 避免在同一行声明不同类型的多个变量
这样可以使程序更加清晰,避免混乱
private int index, index1[]; |
正确的应该如此:
private int index;
private int index1[]; |
(4) 在每一行里写一条语句
这条规则不包括for语句:比如:'for (int i = 0; i < 10; i++) x--;’可以增加代码的可读性。
public class OSPL {
int method (int a, int b) {
int i = a + b; return i; // 可读性不强
} |
正确的:
public class OSPLFixed {
int method (int a, int b) {
int i = a + b;
return i;
}
} |
(5)经常从finalize ()中调用super.finalize ()
这里的finalize ()是java在进行垃圾收集的时候调用的,和finally不一样。如果你的父类没有定义finally()的话,你也应该调用。这里有两个原因:(1)在不改变代码的情况下能够将父类的finally方法加到你的类中。(2)以后你会养成习惯调用父类的finally方法,即使父类没有定义finally方法的时候。
正确的方法应该如此:
public class parentFinalize {
protected void finalize () throws Throwable {
super.finalize(); // FIXED
} |
(6) 不要在finalize ()中注销listeners
不要再finalize ()方法中中注销listeners,finalize ()只有再没有对象引用的时候调用,如果listeners从finalize()方法中去除了,被finalize的对象将不会在垃圾收集中去除。
public void finalize () throws Throwable {
bButton.removeActionListener (act);
} |
(7) 不要显式的调用finalize ()方法
虽然显式的调用这个方法可以使你确保你的调用,但是当这个方法收集了以后垃圾收集会再收集一次。
public class T7 {
public void finalize() throws Throwable {
close_resources ();
super.finalize ();
}
public void close_resources() {}
}
class Test {
void cleanup () throws Throwable {
t71.finalize(); // 调用
t71 = null;
}
private t71 = new T7 ();
} |
对于这样的调用我们应该自己创建一个释放的方法,做最初finalize ()所作的事情,当你每次想显式的调用finalize ()的时候实际上调用了释放方法。然后再使用一个判断字段来确保这个方法只执行一次,以后再调用就没关系了。
public class T7 {
public synchronized void release () throws Throwable{
if (!_released) {
close_resources (); // do what the old 'finalize ()'
did _released = true;
}
}
public void finalize () throws Throwable {
release ();
super.finalize ();
}
public void close_resources() {}
private boolean _released = false;
}
class TestFixed {
void closeTest () throws Throwable {
t71 .release (); // FIXED
t71 = null;
}
private T7 t71 = new T7 ();
} |
(8)不要使用不推荐的API
尽量使用JDK1.3推荐的API。在类和方法或者java组件里有很多方法是陈旧的或者是可以选择的。有一些方法SUN用了"deprecated“标记。最好不要使用例如:
private List t_list = new List ();
t_list.addItem (str); |
如果查一下javadoc的话,会发现建议用add()来代替addItem()。
(9)为所有序列化的类创建一个'serialVersionUID'
可以避免从你各种不同的类破坏序列的兼容性。如果你不特别制订一个UID的话,那么系统为自动产生一个UID(根据类的内容)。如果UID在你新版本的类中改变了,即使那个被序列化的类没改变,你也不能反序列化老的版本了。
public class DUID implements java.io.Serializable { public void method () {}} |
在里面加一个UID,当这个类的序列化形式改变的时候,你也改变这个UID就可以了。
public class DUIDFixed implements java.io.Serializable {
public void method () {}
private static final long serialVersionUID = 1;
} |
(10)对于private常量的定义
比较好的做法是对于这样的常量,加上final标记,这样的常量从初始化到最后结束值都不会改变。
改变后的做法是:
private final int size = 5; |
(11)避免把方法本地变量和参数定义成和类变量相同的名字
这样容易引起混扰,建议把任何的变量字都定义成唯一的。这样看来,SCJP里的那些题目在现实中就用不到了:)
public void method (int j) { final int i = 5; // VIOLATION } private int j = 2; |
建议:
public void method (int j1) { final int i = 5; // VIOLATION } private int j = 2; |
1. 应用范围
本规范应用于采用J2EE规范的项目中,所有项目中的JAVA代码(含JSP,SERVLET,JAVABEAN,EJB)均应遵守这个规范。同时,也可作为其它项目的参考。
2. 设计类和方法
2.1 创建具有很强内聚力的类
方法的重要性往往比类的重要性更容易理解,方法是指执行一个统一函数的一段代码。类常被错误的视为是一个仅仅用于存放方法的容器。有些开发人员甚至把这种思路作了进一步的发挥,将他们的所有方法放入单个类之中。
之所以不能正确的认识类的功能,原因之一是类的实现实际上并不影响程序的执行。当一个工程被编译时,如果所有方法都放在单个类中或者放在几十个类中,这没有任何关系。虽然类的数量对代码的执行并无太大的影响,但是当创建便于调试和维护的代码时,类的数量有时会带来很大的影响。
类应该用来将相关的方法组织在一起。
当类包含一组紧密关联的方法时,该类可以说具有强大的内聚力。当类包含许多互不相关的方法时,该类便具有较弱的内聚力。应该努力创建内聚力比较强的类。
大多数工程都包含许多并不十分适合与其他方法组合在一起的方法。在这种情况下,可以为这些不合群的方法创建一个综合性收容类。
创建类时,应知道“模块化”这个术语的含义是什么。类的基本目的是创建相当独立的程序单元。
2.2 创建松散连接和高度专用的方法
1. 使所有方法都执行专门的任务
每个方法都应执行一项特定的任务,它应出色的完成这项任务。应避免创建执行许多不同任务的方法。
创建专用方法有许多好处。首先调试将变得更加容易。
2. 尽量使方法成为自成一体的独立方法
当一个方法依赖于其他方法的调用时,称为与其他方法紧密连接的方法。紧密连接的方法会使调试和修改变得比较困难,因为它牵涉到更多的因素。松散连接的方法优于紧密连接的方法,但你不可能使每个方法都成为独立的方法。
若要使方法具备较强的独立性,方法之一是尽量减少类变量。
创建方法时,设法将每个方法视为一个黑箱,其他例程不应要求了解该方法的内部工作情况,该方法也不应要求了解它外面的工程情况。这就是为什么你的方法应依靠参数而不应依靠全局变量的原因。
创建专用方法时,请考虑下列指导原则:
1) 将复杂进程放入专用方法。如果应用程序使用复杂的数学公式,请考虑将每个公式放入它自己的方法中。这样使用这些公式的其他方法就不包含用于该公式的实际代码。这样也可以更容易发现与公式相关的问题。
2) 将数据输入/输出(I/O)放入专用方法。
3) 将专用方法中可能要修改的代码隔离。如果你知道某个进程经常变更,请将这个多变的代码放入专用方法,以便以后可以更容易的进行修改,并减少无意中给其他进程带来问题的可能性。
4) 将业务规则封装在专用方法中。业务规则常属于要修改的代码类别,应与应用程序的其余部分隔开。其他方法不应知道业务规则,只有要调用的方法才使用这些规则。
3. 设计类和方法时,要达到下列目的:
1) 创建更加容易调试和维护的方法
2) 创建具有强大内聚力的类
3) 创建高度专用的方法
4) 创建松散连接的方法
5) 尽量使方法具有独立性
6) 提高方法的扇入性
7) 降低方法的扇出性
2.3 编程原则
1. 为方法和类赋予表义性强的名字
为了使代码更加容易理解,最容易的方法之一是为你的方法赋予表义性强的名字。函数名DoIt、GetIt的可读性很难与CalculateSalesTax、 RetrieveUserID相比。
由缩写方法名组成的代码很难理解和维护,没有理由再这样做了。
给方法正确的命名,可使程序工程的调试和维护工作大大的改观。请认真对待方法命名的工作,不要为了减少键入操作量而降低方法的可理解度。
实际应用举例:
1) 给方法命名时应大小写字母混合使用。如果句子全使用大写字母,那么阅读起来就非常困难,而大小写字母混合使用的句子,阅读起来就很容易。
2) 定义方法名时不要使用缩写。如果你认为应用程序中的某些工程应使用缩写,那么请将这些情况加上注释,并确保每个人在所有时间内都使用这些缩写。决不要在某些方法中对某些单词进行缩写,而在别的方法中却不使用缩写。
2. 为每个方法赋予单个退出点
3. 创建方法时,始终都应显式地定义它的作用域。
1) 如果你真的想创建一个公用方法,请向代码阅读者说明这一点。
2) 通过为每个方法赋予一个明确定义的作用域,可以减少代码阅读者需要投入的工作量。应确保你为方法赋予最有意义的作用域。如果一个方法只被同一类中的另一个方法调用,那么请将它创建成私有方法。如果该方法是从多个类中的多个方法中调用,请将该说明为公用方法。
4. 用参数在方法之间传递数据
应尽量避免使用类变量。一般来说,变量的作用域越小越好。为了减少类变量,方法之一是将数据作为参数在不同方法之间传递,而不是让方法共享类变量。
1) 为每个参数指定数据类型。
2) 始终要对数进行检验,决不要假设你得数据没有问题。程序员常犯的一个错误是在编写方法时假设数据没有问题。在初始编程阶段,当编写调用方法时,这样的假设并无大碍。这时你完全能够知道什么是参数的许可值,并按要求提供这些值。但如果你不对参数的数据进行检验,那么下列情况就会给你带来很大麻烦:另外某个人创建了一个调用方法,但此人不知道允许的值;你在晚些时候添加了新的调用方法,并错误的传递了坏数据。
3. 命名约定
所有变量的定义应该遵循匈牙利命名法,它使用3字符前缀来表示数据类型,3个字符的前缀必须小写,前缀后面是由表意性强的一个单词或多个单词组成的名字,而且每个单词的首写字母大写,其它字母小写,这样保证了对变量名能够进行正确的断句。
这样,在一个变量名就可以反映出变量类型和变量所存储的值的意义两方面内容,这使得代码语句可读性强、更加容易理解。
3.1 包、类及方法命名
标示符类型
|
命名约定
|
例子
|
包
|
l 全部小写。
l 标识符用点号分隔开来。为了使包的名字更易读,Sun 公司建议包名中的标识符用点号来分隔。
l Sun 公司的标准 java 分配包用标识符 .java 开头。
l全局包的名字用你的机构的 Internet 保留域名开头。
|
局部包:
interface.screens
全局包:
com.rational.www.interface.screens
|
类,接口
|
l类的名字应该使用名词。
l每个单词第一个字母应该大写。
l 避免使用单词的缩写,除非它的缩写已经广为人知,如HTTP。
|
Class Hello ;
Class HelloWorld ;
Interface Apple ;
|
方法
|
l第一个单词一般是动词。
l 第一个字母是小些,但是中间单词的第一个字母是大写。
l如果方法返回一个成员变量的值,方法名一般为get+成员变量名,如若返回的值是bool变量,一般以is作为前缀。
l如果方法修改一个成员变量的值,方法名一般为:set + 成员变量名。
|
getName();
setName();
isFirst();
|
变量
|
l第一个字母小写,中间单词的第一个字母大写。
l不要用_或&作为第一个字母。
l尽量使用短而且具有意义的单词。
l 单字符的变量名一般只用于生命期非常短暂的变量。i,j,k,m,n一般用于integers;c,d,e一般用于characters。
l如果变量是集合,则变量名应用复数。
l 命名组件采用匈牙利命名法,所有前缀均应遵循同一个组件名称缩写列表。
|
String myName;
int[] students;
int i;
int n;
char c;
btNew;
(bt是Button的缩写)
|
常量
|
l 所有常量名均全部大写,单词间以‘_’隔开。
|
int MAX_NUM;
|
3.2 其它
开发人员如果遇到上述表格中未列举的类型,请书面通知相关管理人员,由管理人员集中更新列表内容,不得擅自启用未经确定的新变量前缀。
4. 使用常量
4.1 使用常量
1. 常数很容易在数据输入时出错
常数存在的主要问题之一是你很容易在键入数字时出错,从而颠倒了数字的位置。例如,当你键入数字10876时,很容易的键入10867或18076。与处理变量和保留字的方法不同,编译器并不在乎颠倒了位置和不正确的数字,有时简单的错误造成的问题不会立即表现出来,而当问题表现出来时,它们会以随机的计算错误的形式出现,这些错误很难准确定位。用常量来取代常数时,编译器将在编译时检查常量的有效性。如果常量不存在,编译器便将这一情况通知你,并拒绝进行编译,这可以消除错误键入的数字带来的问题,只要常量拥有正确的值,使用该常量的所有代码也有使用该正确值。
2. 常数很难不断更新
3. 常量使代码更容易阅读
使用常量后,得到的一个额外好处是可使创建的代码更容易阅读。常数很不直观。也许你对常数非常了解,但其他人则根本看不明白。通过合理的给常量命名,使用这些常量的代码就变得比较直观了,更容易阅读。
为常量赋予较宽的作用域,这与使用变量时的情况不同。在一个应用程序中你决不应该两次创建相同的常量。如果你发现自己复制了一个常量,请将原始的常量说明转至较宽的作用域,直到该常量可供引用它的所有方法为止。
5. 变量
5.1 定义有焦点的变量
用于多个目的的变量称为无焦点(多焦点)的变量。无焦点变量所代表的意义与程序的执行流程有关,当程序处于不同位置时,它所表示的意义是不固定的,这样就给程序的可读性和可维护性带来了麻烦。
5.2 只对常用变量名和长变量名进行缩写
如果需要对变量名进行缩写时,一定要注意整个代码中缩写规则的一致性。例如,如果在代码的某些区域中使用Cnt,而在另一些区域中又使用Count,就会给代码增加不必要的复杂性。
变量名中尽量不要出现缩写。
5.3 使用统一的量词
通过在结尾处放置一个量词,就可创建更加统一的变量,它们更容易理解,也更容易搜索。例如,请使用strCustomerFirst和strCustomerLast,而不要使用strFirstCustomer和strLastCustomer。
量词列表:
量词后缀
|
说明
|
First
|
一组变量中的第一个
|
Last
|
一组变量中的最后一个
|
Next
|
一组变量中的下一个变量
|
Prev
|
一组变量中的上一个
|
Cur
|
一组变量中的当前变量
|
5.4 使用肯定形式的布尔变量
给布尔变量命名时,始终都要使用变量的肯定形式,以减少其它开发人员在理解布尔变量所代表的意义时的难度。
5.5 为每个变量选择最佳的数据类型
这样即能减少对内存的需求量,加快代码的执行速度,又会降低出错的可能性。用于变量的数据类型可能会影响该变量进行计算所产生的结果。在这种情况下,编译器不会产生运行期错误,它只是迫使该值符合数据类型的要求。这类问题极难查找。
5.6 尽量缩小变量的作用域
如果变量的作用域大于它应有的范围,变量可继续存在,并且在不再需要该变量后的很长时间内仍然占用资源。
它们的主要问题是,任何类中的任何方法都能对它们进行修改,并且很难跟踪究竟是何处进行修改的。
占用资源是作用域涉及的一个重要问题。对变量来说,尽量缩小作用域将会对应用程序的可靠性产生巨大的影响。
6. 代码的格式化
6.1 对代码进行格式化时,要达到的目的
1. 通过代码分割成功能块和便于理解的代码段,使代码更容易阅读和理解;
2. 使用空行和注释行,将程序中逻辑上不相关的代码块分开。比如:变量声明部分和代码语句间的分隔;较长的方法中,完成不同功能的代码块间的分隔。要避免出现逻辑上混乱的分隔,如:某一逻辑功能代码块中间用空行进行了分隔,但是在相邻功能代码块之间却没有分隔,这样会给程序阅读者造成错觉。
3. 减少为理解代码结构而需要做的工作;
4. 使代码的阅读者不必进行假设;
5. 使代码结构尽可能做到格式清楚明了。
6.2 编程原则
1. 要将多个语句放在同一行上
不论是变量声明,还是语句都不要在一行上书写多个。
2. 缩进后续行
当你将变量设置为某个值时,所有后续行的缩进位置应与第一行的变量值相同;
当你调用一个方法时,后续行缩进到第一个参数的开始处;
当你将变量或属性设置为等于表达式的计算结果时,请从后面分割该语句,以确保该表达式尽可能放在同一行上。
3. 在if语句后缩进;
在else语句后缩进
在switch语句后缩进
在case语句后缩进
在do句后缩进
已经用行接续符分割的语句的各个行要缩进
对从属于行标注的代码进行缩进。
4. 在执行统一任务的各个语句组之间插入一个空行。好的代码应由按逻辑顺序排列的进程或相关语句组构成。
7. 代码的注释
7.1 使用代码注释的目的
1. 文字说明代码的作用(即为什么要用编写该代码,而不是如何编写);
2. 确指出该代码的编写思路和逻辑方法;
3. 人们注意到代码中的重要转折点;
4. 使代码的阅读者不必在他们的头脑中仿真运行代码的执行方法.
7.2 编程原则
1. 用文字说明代码的作用:
简单的重复代码做写什么,这样的注释几乎不能给注释增加什么信息.如果你使用好的命名方法来创建直观明了的代码那么这些类型的注释绝对增加不了什么信息.
2. 如果你想违背好的编程原则,请说明为什么
有的时候你可能需要违背好的编程原则,或者使用了某些不正规的方法,.遇到这种情况时,请用内部注释来说明你在做什么和为什么要这样做。
技巧性特别高的代码段,一定要加详细的注释,不要让其他开发人员花很长时间来研究一个高技巧但不易理解的程序段。
3. 用注释来说明何时可能出错和为什么出错
4. 在编写代码前进行注释
给代码加注释的方法之一是在编写一个方法前首先写上注释.如果你愿意,可以编写完整句子的注释或伪代码.一旦你用注释对代码进行了概述,就可以在注释之间编写代码.
5. 在要注释的代码前书写注释
注释一定出现在要注释的程序段前,不要在某段程序后书写对这段程序的注释,先看到注释对程序的理解会有一定帮助。
如果有可能,请在注释行与上面代码间加一空行。
6. 纯色字符注释行只用于主要注释
注释中要分隔时,请使用一行空注释行来完成,不要使用纯色字符,以保持版面的整洁、清晰。
7. 避免形成注释框
用星号围成的注释框,右边的星号看起来很好,但它们给注释增加了任何信息吗?实际上这会给编写或编辑注释的人增加许多工作。
8. 增强注释的可读性
注释是供人阅读的,而不是让计算机阅读的。
1) 使用完整的语句。虽然不必将注释分成段落(最好也不要分成段落),但你应尽量将注释写成完整的句子。
2) 避免使用缩写。缩写常使注释更难阅读,人们常用不同的方法对相同的单词进行缩写,这会造成许多混乱,如果必须对词汇缩写,必须做到统一。
3) 将整个单词大写,以突出它们的重要性。若要使人们注意注释中的一个或多个单词,请全部使用大写字母。
9. 对注释进行缩进,使之与后随的语句对齐。
注释通常位于它们要说明的代码的前面。为了从视觉上突出注释与它的代码之间的关系,请将注释缩进,使之与代码处于同一个层次上。
10. 为每个方法赋予一个注释标头
每个方法都应有一个注释标头。方法的注释标头可包含多个文字项,比如输入参数、返回值、原始作者、最后编辑该方法的程序员、上次修改日期、版权信息。
11. 当行尾注释用在上面这种代码段结构中时,它们会使代码更难阅读。
使用多个行尾注释时(比如用于方法顶部的多个变量说明),应使它们互相对齐。这可使它们稍容易阅读一些。
12. 何时书写注释
1) 请在每个if语句的前面加上注释。
2) 在每个switch语句的前面加上注释。与if语句一样,switch语句用于评估对程序执行产生影响的表达式。
3) 在每个循环的前面加上注释。每个循环都有它的作用,许多情况下这个作用不清楚直观。
7.3 注释那些部分
项目
|
注释哪些部分
|
实参/
参数
|
参数类型
参数用来做什么
任何约束或前提条件
示例
|
字段/
字段/属性
|
字段描述
注释所有使用的不变量
示例
并行事件
可见性决策
|
类
|
类的目的
已知的问题
类的开发/维护历史
注释出采用的不变量
并行策略
|
编译单元
|
每一个类/类内定义的接口,含简单的说明
文件名和/或标识信息
版权信息
|
接口
|
目的
它应如何被使用以及如何不被使用
|
局部变量
|
用处/目的
|
成员函数注释
|
成员函数做什么以及它为什么做这个
哪些参数必须传递给一个成员函数
成员函数返回什么
已知的问题
任何由某个成员函数抛出的异常
可见性决策
成员函数是如何改变对象的
包含任何修改代码的历史
如何在适当情况下调用成员函数的例子适用的前提条件和后置条件
|
成员函数内部注释
|
控制结构
代码做了些什么以及为什么这样做
局部变量
难或复杂的代码
处理顺序
|
7.4 示例
7.4.1 块注释:
主要用来描述文件,类,方法,算法等。一般用在文档和方法的前面,也可以放在文档的任何地方。以‘/*’开头,‘*/’结尾。例:
……
/*
* 注释
*/
……
7.4.2 行注释:
主要用在方法内部,对代码,变量,流程等进行说明。与块注释格式相似,但是整个注释占据一行。例:
……
/* 注释 */
……
7.4.3 尾随注释:
与行注释功能相似,放在代码的同行,但是要与代码之间有足够的空间,便于分清。例:
int m=4 ; /* 注释 */
如果一个程序块内有多个尾随注释,每个注释的缩进应该保持一致。
7.4.4 行尾注释:
与行注释功能相似,放在每行的最后,或者占据一行。以‘//’开头。
7.4.5 文档注释:
与块注释相似,但是可以被javadoc处理,生成HTML文件。以‘/**’开头,‘*/’结尾。文档注释不能放在方法或程序块内。例:
/**
注释
*/
8. 表达式和语句
8.1 每行应该只有一条语句。
8.2 if-else,if-elseif语句,任何情况下,都应该有“{”,“}”,格式如下:
if (condition) {
statements;
} else if (condition) {
statements;
} else{
statements;
}
8.3 for语句格式如下:
for (initialization; condition; update) {
statements;
}
如果语句为空:
for (initialization; condition; update) ;
8.4 while语句格式如下:
while (condition) {
statements;
}
如果语句为空:
while (condition);
8.5 do-while语句格式如下:
do {
statements;
} while (condition);
8.6 switch语句,每个switch里都应包含default子语句,格式如下:
switch (condition) {
case ABC:
statements;
/* falls through */
case DEF:
statements;
break;
case XYZ:
statements;
break;
default:
statements;
break;
}
8.7 try-catch语句格式如下:
try {
statements;
} catch (ExceptionClass e) {
statements;
} finally {
statements;
}
9. 错误处理和异常事件
通常的思想是只对错误采用异常处理:逻辑和编程错误,设置错误,被破坏的数据,资源耗尽,等等。
通常的法则是系统在正常状态下以及无重载和硬件失效状态下,不应产生任何异常。异常处理时可以采用适当的日志机制来报告异常,包括异常发生的时刻。不要使用异常实现来控制程序流程结构。
10. 封装、事务
1. 非商务公用组件单独封装
2. 每一个业务流程单独封装
3. 一次方法(组件)的调用应能完成某一项功能或流程,即符合完整性
4. 一次方法(组件)的调用符合ACID事务性
5. 多次方法(组件)的调用应包含在一个事务中
11. 可移植性
1. 尽量不要使用已经被标为不赞成使用的类或方法。
2. 如果需要换行的话,尽量用 println 来代替在字符串中使用""n"。
3. 用separator()方法代替路径中的”/”或”"” 。
4. 用pathSeptarator()方法代替路径中的 ” : ” 或 ” ;” 。
JAVA规范
设计类和方法
==================
创建具有很强内聚力的类
方法的重要性往往比类的重要性更容易理解,方法是指执行一个统一函数的一段代码。类常被错误的视为是一个仅仅用于存放方法的容器。有些开发人员甚至把这种思路作了进一步的发挥,将他们的所有方法放入单个类之中。 之所以不能正确的认识类的功能,原因之一是类的实现实际上并不影响程序的执行。当一个工程被编译时,如果所有方法都放在单个类中或者放在几十个类中,这没有任何关系。虽然类的数量对代码的执行并无太大的影响,但是当创建便于调试和维护的代码时,类的数量有时会带来很大的影响。
类应该用来将相关的方法组织在一起。 当类包含一组紧密关联的方法时,该类可以说具有强大的内聚力。当类包含许多互不相关的方法时,该类便具有较弱的内聚力。应该努力创建内聚力比较强的类。 大多数工程都包含许多并不十分适合与其他方法组合在一起的方法。在这种情况下,可以为这些不合群的方法创建一个综合性收容类。
创建类时,应知道“模块化”这个术语的含义是什么。类的基本目的是创建相当独立的程序单元。
创建松散连接和高度专用的方法
1) 所有方法都执行专门的任务
每个方法都应执行一项特定的任务,它应出色的完成这项任务。应避免创建执行许多不同任务的方法。 创建专用方法有许多好处。首先调试将变得更加容易。
2) 尽量使方法成为自成一体的独立方法
当一个方法依赖于其他方法的调用时,称为与其他方法紧密连接的方法。紧密连接的方法会使调试和修改变得比较困难,因为它牵涉到更多的因素。松散连接的方法优于紧密连接的方法,但你不可能使每个方法都成为独立的方法。
若要使方法具备较强的独立性,方法之一是尽量减少类变量。 创建方法时,设法将每个方法视为一个黑箱,其他例程不应要求了解该方法的内部工作情况,该方法也不应要求了解它外面的工程情况。这就是为什么你的方法应依靠参数而不应依靠全局变量的原因。
3) 创建专用方法时,请考虑下列指导原则:
(1) 将复杂进程放入专用方法。如果应用程序使用复杂的数学公式,请考虑将每个公式放入它自己的方法中。这样使用这些公式的其他方法就不包含用于该公式的实际代码。这样也可以更容易发现与公式相关的问题。
(2) 将数据输入/输出(I/O)放入专用方法。
(3) 将专用方法中可能要修改的代码隔离。如果你知道某个进程经常变更,请将这个多变的代码放入专用方法,以便以后可以更容易的进行修改,并减少无意中给其他进程带来问题的可能性。
(4) 将业务规则封装在专用方法中。业务规则常属于要修改的代码类别,应与应用程序的其余部分隔开。其他方法不应知道业务规则,只有要调用的方法才使用这些规则。
4) 设计类和方法时,要达到下列目的:
1) 创建更加容易调试和维护的方法
2) 创建具有强大内聚力的类
3) 创建高度专用的方法
4) 创建松散连接的方法
5) 尽量使方法具有独立性
6) 提高方法的扇入性
7) 降低方法的扇出性
编程原则
==================
为方法和类赋予表义性强的名字
为了使代码更加容易理解,最容易的方法之一是为你的方法赋予表义性强的名字。函数名DoIt、GetIt的可读性很难与CalculateSalesTax、 RetrieveUserID相比。 由缩写方法名组成的代码很难理解和维护,没有理由再这样做了。 给方法正确的命名,可使程序工程的调试和维护工作大大的改观。请认真对待方法命名的工作,不要为了减少键入操作量而降低方法的可理解度。 实际应用举例:
1) 给方法命名时应大小写字母混合使用。如果句子全使用大写字母,那么阅读起来就非常困难,而大小写字母混合使用的句子,阅读起来就很容易。
2) 定义方法名时不要使用缩写。如果你认为应用程序中的某些工程应使用缩写,那么请将这些情况加上注释,并确保每个人在所有时间内都使用这些缩写。决不要在某些方法中对某些单词进行缩写,而在别的方法中却不使用缩写。
为每个方法赋予单个退出点
创建方法时,始终都应显式地定义它的作用域
1) 如果你真的想创建一个公用方法,请向代码阅读者说明这一点。
2) 通过为每个方法赋予一个明确定义的作用域,可以减少代码阅读者需要投入的工作量。应确保你为方法赋予最有意义的作用域。如果一个方法只被同一类中的另一个方法调用,那么请将它创建成私有方法。如果该方法是从多个类中的多个方法中调用,请将该说明为公用方法。
用参数在方法之间传递数据
应尽量避免使用类变量。一般来说,变量的作用域越小越好。为了减少类变量,方法之一是将数据作为参数在不同方法之间传递,而不是让方法共享类变量。
1) 为每个参数指定数据类型。
2) 始终要对数进行检验,决不要假设你得数据没有问题。程序员常犯的一个错误是在编写方法时假设数据没有问题。在初始编程阶段,当编写调用方法时,这样的假设并无大碍。这时你完全能够知道什么是参数的许可值,并按要求提供这些值。但如果你不对参数的数据进行检验,那么下列情况就会给你带来很大麻烦:另外某个人创建了一个调用方法,但此人不知道允许的值;你在晚些时候添加了新的调用方法,并错误的传递了坏数据。
命名约定
==================
变量的定义
变量的定义应该遵循匈牙利命名法,它使用3字符前缀来表示数据类型,3个字符的前缀必须小写,前缀后面是由表意性强的一个单词或多个单词组成的名字,而且每个单词的首写字母大写,其它字母小写,这样保证了对变量名能够进行正确的断句。 这样,在一个变量名就可以反映出变量类型和变量所存储的值的意义两方面内容,这使得代码语句可读性强、更加容易理解。
包、类及方法命名
1) 包
全部小写。 标识符用点号分隔开来。为了使包的名字更易读,Sun 公司建议包名中的标识符用点号来分隔。
Sun 公司的标准 java 分配包用标识符 .java 开头。
全局包的名字用你的机构的 Internet 保留域名开头 。
局部包: interface.screens
全局包: com.rational.www. interface.screens
2) 类,接口
类的名字应该使用名词。
每个单词第一个字母应该大写。
避免使用单词的缩写,除非它的缩写已经广为人知,如HTTP。
Class Hello ;
Class HelloWorld ;
Interface Apple ;
3) 方法
第一个单词一般是动词。
第一个字母是小些,但是中间单词的第一个字母是大写。
如果方法返回一个成员变量的值,方法名一般为get+成员变量名,如若返回的值是bool变量,一般以is作为前缀。
如果方法修改一个成员变量的值,方法名一般为:set + 成员变量名。
getName(); setName(); isFirst();
4) 变量
第一个字母小写,中间单词的第一个字母大写。
不要用_或&作为第一个字母。
尽量使用短而且具有意义的单词。
单字符的变量名一般只用于生命期非常短暂的变量。i,j,k,m,n一般用于integers;c,d,e一般用于characters。
如果变量是集合,则变量名应用复数。
命名组件采用匈牙利命名法,所有前缀均应遵循同一个组件名称缩写列表。
String myName; int[] students; int i; int n; char c; btNew; (bt是Button的缩写)
5) 常量
所有常量名均全部大写,单词间以‘_’隔开。 int MAX_NUM;
6) 其它
开发人员如果遇到上述表格中未列举的类型,请书面通知相关管理人员,由管理人员集中更新列表内容,不得擅自启用未经确定的新变量前缀。
MVC规范
==================
分层
在MVC的设计模式中,要求在Application开发中你把商业逻辑,界面显示,数据分离。也就是分别在Model,View,Controller实现:数据,控制(商业逻辑)显示(页面显示)。
规则
1) 用户的所有请求统一由控制器截获
2) 控制器根据请求种类,调用不同的业务对象(业务bean),根据业务对象的返回值,来决定该把哪个页面相应给用户
3) 在jsp中,不会出现任何业务代码/数据库操作。可以有实例化bean的操作,或者从session、数据bean中取得数据
4) 在作为控制器的servlet中不会出现网页内容、业务代码、数据库操作。可以有接受request值、实例化bean、调用bean的方法、页面转移
5) 数据bean对应数据库中某张表里的一条记录,这张表中的所有列都应该成为数据bean的私有属性
6) 业务bean在Controller(servlet)中实例化
7) 数据bean在业务bean或Controller中实例化
其它规范
==================
Java文件样式
所有的 Java(*.java) 文件都必须遵守如下的样式规则
1) 版权信息
版权信息必须在 java 文件的开头,比如:
/**
* Copyright ® 2000 Shanghai XXX Co. Ltd.
* All right reserved.
*/
其他不需要出现在 javadoc 的信息也可以包含在这里。
2) Package/Imports
package 行要在 import 行之前,import 中标准的包名要在本地的包名之前,而且按照字母顺序排列。如果 import 行中包含了同一个包中的不同子目录,则应该用 * 来处理。
package hotlava.net.stats;
import java.io.*;
import java.util.Observable;
import hotlava.util.Application;
这里 java.io.* 使用来代替InputStream and OutputStream 的。
3) Class
(1) 类的注释
接下来的是类的注释,一般是用来解释类的。
/**
* A class representing a set of packet and byte counters
* It is observable to allow it to be watched, but only
* reports changes when the current set is complete
*/
(2) 类定义
(3) 类的成员变量
接下来是类的成员变量:
/**
* Packet counters
*/
protected int[] packets;
public 的成员变量必须生成文档(JavaDoc)。
proceted、private和 package 定义的成员变量如果名字含义明确的话,可以没有注释。
(4) 构造函数
接下来是构造函数,它应该用递增的方式写(比如:参数多的写在后面)。
(5) 类方法
下面开始写类的方法:
/**
* Set the packet counters
* (such as when restoring from a database)
*/
protected final
void setArray(int[] r1, int[] r2, int[] r3, int[] r4)
throws IllegalArgumentException
{
//
// Ensure the arrays are of equal size
//
if (r1.length != r2.length || r1.length != r3.length || r1.length != r4.length)
throw new IllegalArgumentException("Arrays must be of the same size");
System.arraycopy(r1, 0, r3, 0, r1.length);
System.arraycopy(r2, 0, r4, 0, r1.length);
}
数组的命名
数组应该总是用下面的方式来命名:
byte[] buffer;
而不是:
byte buffer[];
垃圾收集
JAVA使用成熟的后台垃圾收集技术来代替引用计数。但是这样会导致一个问题:你必须在使用完对象的实例以后进行清场工作。比如一个prel的程序员可能这么写:
.{
FileOutputStream fos = new FileOutputStream(projectFile);
project.save(fos, "IDE Project File");
}
...
除非输出流一出作用域就关闭,非引用计数的程序语言,比如JAVA,是不能自动完成变量的清场工作的。必须象下面一样写:
FileOutputStream fos = new FileOutputStream(projectFile);
project.save(fos, "IDE Project File");
fos.close();
性能
在写代码的时候,从头至尾都应该考虑性能问题。这不是说时间都应该浪费在优化代码上,而是我们时刻应该提醒自己要注意代码的效率。比如:如果没有时间来实现一个高效的算法,那么我们应该在文档中记录下来,以便在以后有空的时候再来实现她。不是所有的人都同意在写代码的时候应该优化性能这个观点的,他们认为性能优化的问题应该在项目的后期再去考虑,也就是在程序的轮廓已经实现了以后。
1) 使用 StringBuffer 对象
在处理 String 的时候要尽量使用 StringBuffer 类,StringBuffer 类是构成 String 类的基础。String 类将 StringBuffer 类封装了起来,(以花费更多时间为代价)为开发人员提供了一个安全的接口。当我们在构造字符串的时候,我们应该用 StringBuffer 来实现大部分的工作,当工作完成后将 StringBuffer 对象再转换为需要的 String 对象。比如:如果有一个字符串必须不断地在其后添加许多字符来完成构造,那么我们应该使用 StringBuffer 对象和她的 append() 方法。如果我们用String 对象代替 StringBuffer 对象的话,会花费许多不必要的创建和释放对象的 CPU 时间。
2) 避免太多的使用 synchronized 关键字
避免不必要的使用关键字 synchronized,应该在必要的时候再使用她,这是一个避免死锁的好方法。
1:了解MVC
MVC是Model,View,Controller的缩写,MVC是Application开发的设计模式,也就是大家所知道的Model2.在MVC的设计模式中,要求在Application开发中你把商业逻辑,界面显示,数据分离。也就是分别在Model,View,Controller实现:数据,控制(商业逻辑)显示(页面显示).在以前或者说传统的Web Application开发方式当中,如Asp,Php,Jsp(Model 1)开发当中我们在Asp(Php,Jsp)中实现一切,如:从数据库中取到我们需要的数据,并根据数据之间的关联和实际的需要按照某种方式把他显示在页面中以及从页面提交的表单中提取数据,根据商业逻辑从数据库查询相关数据,或者把数据写入数据库。也就是说我们在Asp(Php,Jsp)实现一切包括:界面显示,商业逻辑,数据存取。这样带来的后果就是你所写的Asp(Php,Jsp)
没有层次,并且Html和Script(JavaScript、JScript,Asp、Php、Jsp源代码)相互嵌套.可维护性差,最要命的是在Web Application通常显示一块是由美工完成的,很多时候也是你先写好Asp、Php、Jsp然后美工进行美化,很有可能你发现经过美工处理完以后你的代码已经面目全非了。你不得不把你的代码重新组织。在MVC模式中这个问题的解决办法是:View中负责显示,View一般从Controller得到已经处理过的数据,然后显示在页面当中,应该说这样在Html中嵌套很少的Script.基本上美工的修改不大会废掉你的劳动成果。
2: MVC模式的好处
1) 各施其职,互不干涉
在MVC模式中,三个层各施其职,所以如果一旦哪一层的需求发生了变化,就只需要更改相应的层中的代码而不会影响到其它层中的代码。假如业务发生了变化,如在取文章时可能webmaster把一些文章作了无效标志,不能直接把所有文章取出来,只能取出有效的文章,这时业务就发生了改变。再设想一下,如果这个业务逻辑在100个页面中都要用到,那么MVC模式就体现了它的灵活性。我们可以不更改任何JSP,只要更改model层中的相应类中的SQL语句即可。
2) 有利于开发中的分工
在MVC模式中,由于按层把系统开,那么就能更好的实现开发中的分工。网页设计人员可以进行开发视图层中的JSP,对业务熟悉的开发人员可开发业务层,而其它开发人员可开发控制层。
3) 有利于组件的重用
分层后更有利于组件的重用。如控制层可独立成一个能用的组件,视力层也可做成通用的操作界面。