LCPolSchematLCPolSchema=tLCPolSchema.get(i);
...
}
}
把内层循环提到一个函数中,在编译时就幸免了bug的产生,而且降低了循环的层次,具有更好的可读性。
四、静态方法
1.静态方法的错误使用
com..lis.bq.ChangeCodeBL是保全中的一个工具类,它用两个重载了的静态方法getCodeName,它封装了CodeQueryBL类,其作用是依照code和codeType得到codeName,
然而在使用过程中却显现了如下程序:
ChangeCodeBLtChangeCode=newChangeCodeBL();
strArr[0]="与被保人关系原为"+tChangeCode.getCodeName("relation",
tLCBnfSchema.getRelationToInsured());
明显,作为静态方法getCodeName不应该如此使用,应改为:
strArr[0]="与被保人关系原为"+ChangeCodeBL.getCodeName("relation",
tLCBnfSchema.getRelationToInsured());
之因此显现如此的错误是因为ChangeCodeBL在定义构造函数时出了问题,构造函数的类型写成了public,但那个类实际上是不承诺创建对象的。
因此改为privateChangeCodeBL(){}就能够从全然上幸免错误的产生。
静态方法的另一个常见的应用是用来创建对象,比如工厂模式和单例模式,这时我们同样应该使用pritvate的构造函数。
五、参数
1.对参数进行校验
关于传入类的参数,我们需要对其合法性进行校验,比如:
privatebooleangetInputData(VDatacInputData){
LCGrpContSchematLCGrpContSchema=
(LCGrpContSchema)cInputData.getObjectByObjectName(
"LCGrpContSchema",0);
LCContDBtLCContDB=newLCContDB();
tLCContDB.setGrpContNo(mGrpContSchema.getGrpContNo());
mLCContSet=tLCContDB.query();
returntrue;
}
这段代码是存在风险的,因为我们并不能保证getObjectByObjectName一定会得到一个对象返回,假如"LCGrpContSchema"写错了或者jsp页面全然就没有创建LCGrpContSchema对象,那么tLCGrpContSchema就为null,执行到mGrpContSchema.getGrpContNo()时就会抛出空指针专门。
因此改为:
privatebooleangetInputData(VDatacInputData){
LCGrpContSchematLCGrpContSchema=
(LCGrpContSchema)cInputData.getObjectByObjectName(
"LCGrpContSchema",0);
if(tLCGrpContSchema==null){
...
returnfalse;
}
LCContDBtLCContDB=newLCContDB();
tLCContDB.setGrpContNo(mGrpContSchema.getGrpContNo());
mLCContSet=tLCContDB.query();
returntrue;
}
关于public的方法,我们同样需要对其参数进行校验,因为我们不能保证客户程序的调用是正确的。
2.不对参数进行赋值操作
Java中只有int,long,double等差不多类型的参数是使用值传递,而对象参数差不多上传的地址,因此在函数中对对象参数赋值是无效的。
C语言中由于有指针能够对函数外的对象的值直截了当进行修改,但java不行,因此参数只作为数据的传入而不能作为数据的传出。
六、代码简化
1.除去余外的代码
比如:
LCContDBtLCContDB=newLCContDB();
tLCContDB.setGrpContNo(tGrpContNo);
LCContSettLCContSet=tLCContDB.query();
if((tLCContSet==null)||(tLCContSet.size()==0)){
returnfalse;
}
那个地点tLCContSet==null的判定是余外的,因为tLCContDB.query()确信会创建一个对象返回,不存在返回null的情形,改为if(tLCContSet.size()==0)
又如:
if(tLCPolSet.size()>0){
for(inti=1;i<=tLCPolSet.size();i++){
tLPEdorItemSchema.setPolNo(tLCPolSet.get(i).getPolNo());
if(this.queryLPPol(tLPEdorItemSchema)){
tLPPolSet.add(this.getSchema());
}
}
}
那个地点if(tLCPolSet.size()>0)判定余外,将其除去
2.合并重复的代码
比如:
if(getMoney>0){
strArr[0]="本次申请应补交保费"+
setPrecision(Math.abs(getMoney),2)+"元。
";
tlistTable.add(strArr);
}
else{
strArr[0]="本次申请应退还保费"+
setPrecision(Math.abs(getMoney),2)+"元。
";
tlistTable.add(strArr);
}
那个地点tlistTable.add(strArr);重复,将其提到if别处合并。
七、条件逻辑操纵
1.去除操纵标志
受结构化程序设计的阻碍,有人喜爱用boolean型的标志来操纵程序的流程,比如:
privatebooleancheckMoney(){
booleanflag=true;
if(money>0){
flag=true;
}
else{
flag=false;
}
returnflag;
}
但逻辑标志的使用会降低程序的可读性,当逻辑复杂时修改爱护会比较困难,因此改为:
privatebooleancheckMoney(){
if(money>0){
returntrue;
}
else{
returnflase;
}
}
或者:
privatebooleancheckMonay(){
if(money>0){
returntrue;
}
returnflase;
}
2.位运算符
&和|差不多上位运算符,但它们也可在if语句中进行条件判定,但现在仍是执行的位运算。
因为使用&和|容易引起不必要的错误,因此禁止在条件判定中使用位运算符。
八、专门处理
1.try{}catch{}语句的滥用
java的专门处理机制能够把错误处理程序和正常程序分开,使我们能够更容易进行复杂的错误处理。
但专门处理机制容易被滥用,因为大多数的java书只是描述了专门机制的语法,而并没有说明什么情形下使用专门。
专门之因此是专门是因为其不可预料性,比如我们通过io读取配置文件而文件并不存在,又比如通过jdbc读取数据库服务器却当掉了,这些差不多上需要我们通过专门机制来处理的情形。
而下面的代码对专门的处理是错误的:
privatebooleangetInputData(VDatacInputData){
try{
LCGrpContSchematLCGrpContSchema=
(LCGrpContSchema)cInputData.getObjectByObjectName(
"LCGrpContSchema",0);
}
catch(Exceptione){
CError.buildErr(this,"接收数据失败");
returnfalse;
}
returntrue;
}
因为我们只要看一下getObjectByObjectName的代码就明白那个函数假如处理错误会返回一个null而不是抛出专门,那个地点的try{}catch{}是没有任何意义的,而且会降低程序的性能,因为对专门的捕捉会花去额外的开销。
2.空指针专门
NullPointerException是比较常见的错误,因此我们在使用一个对象前一定要确保那个对象差不多被创建过了。
3.数据格式化专门
使用Integer.parseInt(Strings)进行数据格式转化时假如数据格式错误会抛出NumberFormatException专门,那个专门继承于RuntimeException,是一个非强制捕捉的专门。
但从程序的健壮性考虑,如下代码我们最好能进行专门处理:
将intbnfGrade=Integer.parseInt(tLPBnfSchema.getBnfGrade());改为:
try{
intbnfGrade=Integer.parseInt(tLPBnfSchema.getBnfGrade());
}
catch(NumberFormatExceptione){
...
}
因为那个地点我们并不能保证tLPBnfSchema.getBnfGrade()返回的一定是能够被格式化为整数的字符串。
假如我们有足够的理由确保那个地点可不能产生专门,那么专门处理也可省略,正如前面所说的,专门处理的是不可预料的错误。
4.数组越界
数组越界专门同样容易被滥用,比如:
try{
inti=0;
while(true){
a[i++].f();
}
}
catch(ArrayIndexOutOfBoundsExceptione){
...
}
这种用法是错误的,改为:
intk=a.length;
for(inti=0;ia[i].f();
}
不要试图用专门处理去取代条件判定,我们要做的是把数组越界的条件排除掉而不是等它越界了再去处理专门。
九、接口和抽象类
抽象和继承是面向对象的重要特点,使用接口和抽象类能够使得程序的实现细节得到封装,耦合度降低,更容易随着需求的变化而扩展。
下面对一些需要注意的地点进行说明:
1.只从抽象类继承
使用继承时要慎重,继承代表〝一样化/专门化〞的关系,继承会使子类依靠于父类,假如父类的实现发生改变那么子类的实现将不得不发生改变。
因此,在使用继承时一样不要从具体类继承,只有抽象类才用来继承,因为抽象类能够用抽象方法来提供扩展,而抽象类里的具体方法一定要确保是需求比较固定的部分,以后都可不能有任何的改动。
2.不覆写父类的具体方法
在子类中能够对父类的方法进行重载,也确实是父类里实现了一个方法,子类用同样的函数名去重新实现那个方法。
但这种做法是错误的,子类只应该去实现父类的抽象方法,而不是去实现父类已有的具体方法。
假如需要如此做只能说明父类的方法不能作为具体方法而存在,将它改为抽象方法。
3.不在接口中定义属性
这是保全中的一个bug。
为了使保全算功能便于扩展,定义了EdorAppConfirm接口:
publicinterfaceEdorAppConfirm{
publicCErrorsmErrors=newCErrors();
publicbooleansubmitData(VDatacInputData,StringcOperate);
publicVDatagetResult();
}
然后再实现那个接口,比如:
publicclassGrpEdorNIAppConfirmBLimplementsEdorAppConfirm{
publicCErrorsmErrors=newCErrors();
publicbooleansubmitData(VDatacInputData,StringcOperate){
if(!
dealData()){
returnfalse;
}
...
}
}
最后再调用那个接口:
ClasstClass=Class.forName("com..lis.bq.GrpEdor"+
tEdorType+"AppConfirmBL");
EdorAppConfirmtGrpEdorAppConfirm=(EdorAppConfirm)
tClass.newInstance();
VDatatVData=newVData();
tVData.add(iLPGrpEdorItemSchema);
tVData.add(mLJSGetEndorseSchema);
tVData.add(mGlobalInput);
tVData.add(tLPGrpEdorMainSet);
if(!
tGrpEdorAppConfirm.submitData(tVData,
"APPCONFIRM||"+tEdorType)){
CError.buildErr(this,"保全项目"+tEdorType+
"试算时失败!
失败缘故:
"+tGrpEdorAppConfirm.mErrors.
getFirstError());
returnfalse;
}
那个地点本意是假如算费出错returnfalse并返回错误缘故,但实际上不可能得到错误缘故。
因为EdorAppConfirm和GrpEdorNIAppConfirmBL中都定义了mErrors,现在返回的是接口中的mErrors。
假如把GrpEdorNIAppConfirmBL中的mErrors去掉能够解决那个bug,然而在接口中定义public的属性不是好的做法,因此可考虑把mErrors换成getErrors方法。
4.接口和抽象类的组合使用
当我们预备使用抽象时会考虑是使用接口还使用抽象类,因为它们各有优缺点,接口和抽象类最大的区别是抽象类能够有具体实现而接口是纯抽象的。
假如用抽象类那么写在抽象类中的具体实现代码的改动会导致各级子类的改动,假如使用接口幸免了那个问题但又带来了另一个问题,确实是各个实现接口的子类可能有重复的代码,如爱护也需要爱护多处地点。
因此比较好的方法是先定义一个接口,然后定义一个抽象类来实现那个接口,然后各个具体实现类继承那个抽象类,并把重复的实现代码放到抽象类中。
那个地点要注意的是放到抽象类中的代码一定要是固定的,可不能随需求改动的部分。
十、其它需注意地点
1.clone()的使用
java的clone机制使我们能够专门方便的进行使用对象的复制,只需实现Cloneable接口就行了。
如:
publicclassMyObjectimplementsCloneable{
publicObjectclone(){
try{
returnsuper.clone();
}catch(CloneNotSupportedExceptione){
thrownewInternalError();
}
}
}
但要注意的是java分为深clone和浅clone,它们区别是对象内部的成员属性在clone时是否处理为引用。
假如仍旧保留为引用,那么称为浅clone,反之称为深clone。
而java默认是浅clone,假如要实现深clone还需要对各个成员属性分别进行clone操作。
2.Javascript脚本的执行效率
IE执行脚本取object的length效率是专门低的。
不要在循环结构中的操纵变量上直截了当使用〝XX.length〞,应幸免如下程序段的写法:
vartFlag="";
for(i=0;iif(fm.QueryType[i].checked){
tFlag=fm.QueryType[i].value;
break;
}
}
应改为:
countOfQueryType=fm.QueryType.length;
for(i=0;i当例子中的