电信事业部Java编程规范_第1页
电信事业部Java编程规范_第2页
电信事业部Java编程规范_第3页
电信事业部Java编程规范_第4页
电信事业部Java编程规范_第5页
已阅读5页,还剩30页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

DOCPROPERTY"Company"广州市聚晖电子科技有限公司电信事业部Java项目TITLE编程规范版本<1.0>_____________________________________________说明:此表相关部门签字后,请交与行政人事部审核备案。Page编程指南简介此编程指南的文档用来规范每一个一线开发人员代码的编写,试图确保代码编写的规范化和代码编写的质量,进而提高我们开发的项目的质量和开发团队的编码水平。此编程指南的内容涵盖了从源代码文件的结构、格式,对常见代码要素的格式和内容两个方面的要求,到如何避免长犯的错误,避免bug、如何提高代码的严谨性、可靠性和提高质量等方方面面的内容,需要每一个开发人员在每天的工作中严格遵守。目的提高编码工作的规范性提高完成的代码的规范性避免编写多余、低效、漏洞百出的代码加强开发人员的技术素养、提高开发工作的质量范围这个文档的范围包括:一个源代码文件的内容,应该怎样组织,风格怎样代码中注释的位置、写法、要求包、类、方法、常量、变量、属性等的命名的要求声明的编写要求表达式的编写要求内存管理方面的要求异常处理方面的要求针对可移植性的编程要求针对复用的编程要求这些要求对于提高代码质量、提高代码的规范性有帮助,定义这个规范的目的是让项目中所有的文档都看起来像一个人写的,增加可读性,减少项目组中因为人员变更而带来的损失。这些规范并不是一定要绝对遵守,但是一定要让程序有良好的可读性,需要各开发同事努力遵守。定义、首字母缩写词和缩略语[本小节应提供正确理解此编程指南所需的全部术语、首字母缩写词和缩略语的定义。这些信息可以通过引用项目词汇表来提供。]参考资料Sun公司制定的Java编程规范一些基础Java库,包括JDK、Spring、Apache的一些开业项目的代码编写方式概述文档中接下来的内容首先阐述了关于代码的组织和风格有关的建议,接下来阐述了围绕编写高效率、可移植性、错误处理等论题的一些建议。代码组织与风格每个Java源文件都包含一个单一的公共类或接口。若私有类和接口与一个公共类相关联,可以将它们和公共类放入同一个源文件。公共类必须是这个文件中的第一个类或接口。Java源文件的组织如下:开头注释所有的源文件都应该在开头有一个C语言风格的注释,其中列出类名、版本信息、日期和版权声明:/**Classname**Versioninformation**Date**Copyrightnotice*/包和引入语句package行要在import行之前,两者之间以空行分隔。import中标准的包名要在本地的包名之前,而且按照字母顺序排列。(在Eclipse中,可以用快捷键Ctrl+Shift+O来导入需要的类和清除该类不需要的import语句。)package.stats;importjava.io.*;importjava.util.Observable;importhotlava.util.Application;类的注释接下来的是类的注释,一般用来解释类的作用,形式如下:/***Aclassrepresentingasetofpacketandbytecounters*Itisobservabletoallowittobewatched,butonly*reportschangeswhenthecurrentsetiscomplete*/类声明包括类的访问修饰符、类名、继承的父类、实现的接口等。类的成员变量建议以下面先后顺序组织类成员变量:静态变量(static):首先是类的公共变量(public),随后是保护变量(protected),再后是包一级别的变量(没有访问修饰符),最后是私有变量(private)。实例变量:首先是类的公共变量(public),随后是保护变量(protected),再后是包一级别的变量(没有访问修饰符),最后是私有变量(private)。一般情况下,不鼓励以public的方式定义类的实例变量,对类的实例变量的操作应该通过类的方法,比如getter和setter来进行。public的成员变量必须生成文档(JavaDoc)。proceted、private和package定义的成员变量如果名字含义明确的话,可以没有注释。 /** *Packetcounters */ protectedint[]packets;构造函数构造函数应该用递增的方式写(比如:参数多的写在后面)。类方法静态方法一般放在最前面。类方法应该按功能,而非作用域或访问权限,分组。例如,一个私有的类方法可以置于两个公有的实例方法之间。其目的是为了更便于阅读和理解代码。 /** *Setthepacketcounters(suchaswhenrestoringfromadatabase). * *@paramr1 *@paramr2 *@paramr3 *@paramr4 *@throwsIllegalArgumentException */ protectedfinalvoidsetArray(int[]r1,int[]r2,int[]r3,int[]r4) throwsIllegalArgumentException{ //Ensurethearraysareofequalsize if(r1.length!=r2.length||r1.length!=r3.length ||r1.length!=r4.length) thrownewIllegalArgumentException( "Arraysmustbeofthesamesize"); System.arraycopy(r1,0,r3,0,r1.length); System.arraycopy(r2,0,r4,0,r1.length); }下面JDK中NullPointerException这个类的源代码,是一个很好的示例:/**@(#)NullPointerException.java 1.2005/11/17**Copyright2006SunMicrosystems,Inc.Allrightsreserved.*SUNPROPRIETARY/CONFIDENTIAL.Useissubjecttolicenseterms.*/packagejava.lang;/***Thrownwhenanapplicationattemptstouse<code>null</code>ina*casewhereanobjectisrequired.Theseinclude:*<ul>*<li>Callingtheinstancemethodofa<code>null</code>object.*<li>Accessingormodifyingthefieldofa<code>null</code>object.*<li>Takingthelengthof<code>null</code>asifitwereanarray.*<li>Accessingormodifyingtheslotsof<code>null</code>asifit*wereanarray.*<li>Throwing<code>null</code>asifitwerea<code>Throwable</code>*value.*</ul>*<p>*Applicationsshouldthrowinstancesofthisclasstoindicate*otherillegalusesofthe<code>null</code>object.**@authorunascribed*@version1.20,11/17/05*@sinceJDK1.0*/publicclassNullPointerExceptionextendsRuntimeException{ /** *Constructsa<code>NullPointerException</code>withnodetailmessage. */ publicNullPointerException(){ super(); } /** *Constructsa<code>NullPointerException</code>withthespecified *detailmessage. * *@paramsthedetailmessage. */ publicNullPointerException(Strings){ super(s); }}关于代码组织与风格的推荐示例上面说了这么多,下面以M2M项目中使用的一个实际的class的源代码来说明,我们的代码必须达到的基本水平,如下:/**@(#)UserDetailsServiceImpl.java 1.02008-10-24**Copyright2004-2008广州市聚晖电子有限公司,Inc.Allrightsreserved.*Tri-sunPROPRIETARY/CONFIDENTIAL.Useissubjecttolicenseterms.*/packagecom.trisun.m2m.security;importjava.util.Iterator;importjava.util.List;importorg.acegisecurity.GrantedAuthority;importorg.acegisecurity.GrantedAuthorityImpl;importorg.acegisecurity.userdetails.User;importorg.acegisecurity.userdetails.UserDetails;importorg.acegisecurity.userdetails.UserDetailsService;importorg.acegisecurity.userdetails.UsernameNotFoundException;importorg.springframework.dao.DataAccessException;importmons.lang.StringUtils;importmon.utils.Obfuscator;importcom.trisun.m2m.enums.UserKind;importcom.trisun.m2m.hibernate.BusinessOperatorManagerImpl;importcom.trisun.m2m.hibernate.CustomerManagerImpl;importcom.trisun.m2m.hibernate.ManufacturerOperatorManagerImpl;importcom.trisun.m2m.hibernate.OperatorManagerImpl;importcom.trisun.m2m.model.BusinessOperator;importcom.trisun.m2m.model.Customer;importcom.trisun.m2m.model.ManufacturerOperator;importcom.trisun.m2m.model.Operator;importcom.trisun.m2m.model.Roles;/***实现了Acegi框架的UserDetailService接口,用于在数据库中根据用户名查找用户,<br>*并封装为Acegi框架的UserDetails对象返回给框架。**@author杨济嘉*/publicclassUserDetailsServiceImplimplementsUserDetailsService{/***客户的GrantedAuthority对象*/privatefinalGrantedAuthorityROLE_CUSTOMER=newGrantedAuthorityImpl("ROLE_CUSTOMER");/***运营商操作员的GrantedAuthority对象*/privatefinalGrantedAuthorityROLE_OPERATOR=newGrantedAuthorityImpl("ROLE_OPERATOR");/***业务操作员的GrantedAuthority对象*/privatefinalGrantedAuthorityROLE_BUSINESSOPERATOR=newGrantedAuthorityImpl("ROLE_BUSINESSOPERATOR");/***终端厂商操作员的GrantedAuthority对象*/privatefinalGrantedAuthorityROLE_MANUFACTUREROPERATOR=newGrantedAuthorityImpl("ROLE_MANUFACTUREROPERATOR");/***客户DAO*/privateCustomerManagerImplcustomerManagerImpl;/***运营商操作员DAO*/privateOperatorManagerImploperatorManagerImp;/***业务操作员DAO*/privateBusinessOperatorManagerImplbusinessOperatorManager;/***终端厂商操作员DAO*/privateManufacturerOperatorManagerImplmanufacturerOperatorManager;/***根据用户名查找用户并封装为UserDetails对象返回。**@paramusername用户名*@return存有用户信息的UserDetails对象*@throwsUsernameNotFoundException找不到输入的用户名时抛出这个异常*@throwsDataAccessException访问数据库出错时抛出这个异常*/publicUserDetailsloadUserByUsername(Stringusername)throwsUsernameNotFoundException,DataAccessException{if(StringUtils.isBlank(username)){returnnull;}//获取用户类型UserKinduserKind=UserKindContext.getContext().getUserKind();//根据不同类型用户查找用户switch(userKind){caseCUSTOMER:returnloadCustomerByUsername(username);caseOPERATOR:returnloadOperatorByUsername(username);caseBUSINESS_OPERATOR:returnloadBusinessOperatorByUsername(username);caseMANUFACTURER_OPERATOR:returnloadManufacturerOperatorByUsername(username);default:returnnull;}}/***查找客户。**@paramusername用户名*@return存有客户信息的UserDetails对象*@throwsUsernameNotFoundException找不到输入的用户名时抛出这个异常*@throwsDataAccessException访问数据库出错时抛出这个异常*/@SuppressWarnings("unchecked")privateUserDetailsloadCustomerByUsername(Stringusername)throwsUsernameNotFoundException,DataAccessException{List<Customer>customers=customerManagerImpl.find("fromCustomercwherec.phoneNum=?",username);Stringpassword;if(customers==null||customers.isEmpty()){thrownewUsernameNotFoundException("Customer'"+username+"'notfound");}try{password=Obfuscator.deobfuscate(customers.get(0).getPassword());}catch(RuntimeExceptione){thrownewUsernameNotFoundException("Passwordofcustomer'"+username+"'iswrong");}GrantedAuthority[]authors=newGrantedAuthority[]{ROLE_CUSTOMER};returnnewUser(username,password,true,true,true,true,authors);}/***查找运营商操作员。**@paramusername用户名*@return存有运营商操作员信息的UserDetails对象*@throwsUsernameNotFoundException找不到输入的用户名时抛出这个异常*@throwsDataAccessException访问数据库出错时抛出这个异常*/@SuppressWarnings("unchecked")privateUserDetailsloadOperatorByUsername(Stringusername)throwsUsernameNotFoundException,DataAccessException{List<Operator>operators=operatorManagerImp.find("fromOperatorowhereo.account=?",username);if(operators==null||operators.isEmpty()){thrownewUsernameNotFoundException("Operator'"+username+"'notfound");}Stringpassword;try{password=Obfuscator.deobfuscate(operators.get(0).getPassword());}catch(RuntimeExceptione){thrownewUsernameNotFoundException("Passwordofoperator'"+username+"'iswrong");}java.util.Collection<Roles>roles=operators.get(0).getRoleList();intsize=roles.size();GrantedAuthority[]authors=newGrantedAuthority[size+1];authors[0]=ROLE_OPERATOR;Iterator<Roles>role=roles.iterator();Rolesrs;inti=1;while(role.hasNext()){rs=role.next();authors[i]=newGrantedAuthorityImpl(rs.getRoleName());i++;}returnnewUser(username,password,true,true,true,true,authors);}/***查找业务操作员。**@paramusername用户名*@return存有业务操作员信息的UserDetails对象*@throwsUsernameNotFoundException找不到输入的用户名时抛出这个异常*@throwsDataAccessException访问数据库出错时抛出这个异常*/@SuppressWarnings("unchecked")privateUserDetailsloadBusinessOperatorByUsername(Stringusername)throwsUsernameNotFoundException,DataAccessException{List<BusinessOperator>businessOperators=businessOperatorManager.find("fromBusinessOperatorbwhereb.account=?",username);if(businessOperators==null||businessOperators.isEmpty())thrownewUsernameNotFoundException("BusinessOperator'"+username+"'notfound");Stringpassword;try{password=Obfuscator.deobfuscate(businessOperators.get(0).getPassword());}catch(RuntimeExceptione){thrownewUsernameNotFoundException("PasswordofbusinessOperator'"+username+"'iswrong");}GrantedAuthority[]authors=newGrantedAuthority[]{ROLE_BUSINESSOPERATOR};returnnewUser(username,password,true,true,true,true,authors);}/***查找终端厂商操作员。**@paramusername用户名*@return存有终端厂商操作员信息的UserDetails对象*@throwsUsernameNotFoundException找不到输入的用户名时抛出这个异常*@throwsDataAccessException访问数据库出错时抛出这个异常*/@SuppressWarnings("unchecked")privateUserDetailsloadManufacturerOperatorByUsername(Stringusername)throwsUsernameNotFoundException,DataAccessException{List<ManufacturerOperator>manufacturerOperators=manufacturerOperatorManager.find("fromManufacturerOperatormowheremo.account=?",username);if(manufacturerOperators==null||manufacturerOperators.isEmpty())thrownewUsernameNotFoundException("ManufacturerOperator'"+username+"'notfound");Stringpassword;try{password=Obfuscator.deobfuscate(manufacturerOperators.get(0).getPassword());}catch(RuntimeExceptione){thrownewUsernameNotFoundException("PasswordofmanufacturerOperator'"+username+"'iswrong");}GrantedAuthority[]authors=newGrantedAuthority[]{ROLE_MANUFACTUREROPERATOR};returnnewUser(username,password,true,true,true,true,authors);}//getter&setterpublicCustomerManagerImplgetCustomerManagerImpl(){returncustomerManagerImpl;}publicvoidsetCustomerManagerImpl(CustomerManagerImplcustomerManagerImpl){this.customerManagerImpl=customerManagerImpl;if(null!=customerManagerImpl){this.customerManagerImpl.getHibernateTemplate().setCacheQueries(true);}}publicOperatorManagerImplgetOperatorManagerImp(){returnoperatorManagerImp;}publicvoidsetOperatorManagerImp(OperatorManagerImploperatorManagerImp){this.operatorManagerImp=operatorManagerImp;if(null!=operatorManagerImp){this.operatorManagerImp.getHibernateTemplate().setCacheQueries(true);}}publicBusinessOperatorManagerImplgetBusinessOperatorManager(){returnbusinessOperatorManager;}publicvoidsetBusinessOperatorManager(BusinessOperatorManagerImplbusinessOperatorManager){this.businessOperatorManager=businessOperatorManager;if(null!=businessOperatorManager){this.businessOperatorManager.getHibernateTemplate().setCacheQueries(true);}}publicManufacturerOperatorManagerImplgetManufacturerOperatorManager(){returnmanufacturerOperatorManager;}publicvoidsetManufacturerOperatorManager(ManufacturerOperatorManagerImplmanufacturerOperatorManager){this.manufacturerOperatorManager=manufacturerOperatorManager;if(null!=manufacturerOperatorManager){this.manufacturerOperatorManager.getHibernateTemplate().setCacheQueries(true);}}}基本要求:类必须包含至少含有如下内容的源代码版权声明:/**@(#)UserDetailsServiceImpl.java 1.02008-10-24**Copyright2004-2008广州市聚晖电子有限公司,Inc.Allrightsreserved.*Tri-sunPROPRIETARY/CONFIDENTIAL.Useissubjecttolicenseterms.*/类的注释必须具备,格式如上所述,要尽量说明类的作用,为什么使用它、相关的调用关系以及其它必须说明的问题。属性的说明必须基本,格式如上所述。方法的说明必须基本,格式如上所述。方法的参数的意义、返回值的意义以及有关的需要注意的问题,必须说明。缩进排版代码因适当使用缩进排版提高可读性,一般使用1个制表符(Tab)作为缩进单位。行长度尽量避免一行的长度超过80个字符,因为很多终端和工具不能很好处理。换行当一个表达式无法容纳在一行内时,可以依据如下一般规则断开之:-在一个逗号后面断开-在一个操作符前面断开-宁可选择较高级别(higher-level)的断开,而非较低级别(lower-level)的断开-新的一行应该与上一行同一级别表达式的开头处对齐-如果以上规则导致你的代码混乱或者使你的代码都堆挤在右边,那就代之以缩进2个制表符(Tab)。注释按照下面方式编写注释后,可以很容易生成我们编写的源代码的说明文档,生成后的文档形式如下,可以方便代码的维护,是目前所有Java开发的项目的通用形式:例如,上面类NullPointerException的JavaDoc文档的一部分如下,我们可以很容易地看出和上面的示例中类的注释部分一一对应情况:类的注释在类名所在行的上方输入字符“/**”,如下图所示:然后在下图中,选中的行的位置添加类的注释,说明类的作用、调用关系,要注意的问题等。方法的注释在方法上面输入字符“/**”,如下图所示:然后回车,效果如下图:接下来在被选中的那一行上添加注释就可以了,@return部分描述了方法的返回值,也需要用注释说明。类属性的注释类属性的注释的添加方式和上面提到的类、方法的注释的添加方式一样,正确添加后的效果如下:下面的方式是错误的,只能通过开代码看到:非JavaDoc的注释如果方法中的算法或者业务逻辑比较复杂,除了在方法前使用JavaDoc注释之外,在方法体内也应适当使用非JavaDoc的注释解释清楚方法的实现思路和流程。这些注释可以选择使用“/*...*/”或者是“//...”的形式。命名包、类、方法、属性、变量等的命名对于代码的维护有重要的意义,胡乱命名的代码很容易变成对自己和别人的工作都不利的事情。命名规范使程序更易读,从而更易于理解。它们也可以提供一些有关标识符功能的信息,以助于理解代码。包的命名包的名字应该全部小写的ASCII字母组成。类的命名类名是一个名词,采用大小写混合的方式,每个单词的首字母大写。尽量使你的类名简洁而富于描述。使用完整单词,避免缩写词(除非该缩写词被更广泛使用,像URL,HTML)。接口的命名大小写规则与类相同。方法的命名方法名是一个动词,采用大小写混合的方式,第一个单词的首字母小写,其后单词的首字母大写。变量的命名除了变量名外,所有实例,包括类,类常量,均采用大小写混合的方式,第一个单词的首字母小写,其后单词的首字母大写。变量名不应以下划线或美元符号开头,尽管这在语法上是允许的。变量名应简短且富于描述。变量名的选用应该易于记忆,即,能够指出其用途。尽量避免单个字符的变量名,除非是一次性的临时变量。临时变量通常被取名为i,j,k,m和n,它们一般用于整型;c,d,e,它们一般用于字符型。Final变量(常量)的命名常量的声明,应该全部大写,单词间用下划线隔开。参数的命名参数的名字必须和变量的命名规范一致。声明每行声明变量的数量推荐一行一个声明,因为这样以利于写注释。初始化尽量在声明局部变量的同时初始化。避免覆盖避免声明的局部变量覆盖上一级声明的变量。数组的声明数组的声明应使用“类型[]变量名”的方式而不是“类型变量名[]”的方式。例如应使用“long[]ids”而不是“longids[]”。类和接口的声明当编写类和接口时,应该遵守以下格式规则:-在方法名与其参数列表之前的左括号"("间不要有空格-左大括号"{"位于声明语句同行的末尾-右大括号"}"另起一行,与相应的声明语句对齐-方法与方法之间以空行分隔表达式和语句简单语句每行至多包含一条语句,即使语句很短,也不要把多个语句写到同一行中。复合语句复合语句是包含在大括号中的语句序列,形如"{语句}"。-被括其中的语句应该较之复合语句缩进一个层次-左大括号"{"应位于复合语句起始行的行尾;右大括号"}"应另起一行并与复合语句首行对齐。选择和循环语句if,if-else,ifelse-ifelse语句,for语句,while语句中,即使选择分支或者循环体内只有一个语句,也使用大括号将其括起来,除非循环体为空。这样做的目的一是让程序更容易看懂,二是便于以后在分支或者循环体内添加其他语句。示例://if语句if(condition){ statements;}//if-else语句if(condition){ statements;}else{ statements;}//if-elseif-else语句if(condition){ statements;}elseif(condition){ statements;}else{ statements;}//for语句for(initialization;condition;update){ statements;}//空的for语句for(initialization;condition;update);//while语句while(condition){ statements;}//空的while语句while(condition);//do-while语句do{ statements;}while(condition);switch-case语句每当一个case顺着往下执行时(因为没有break语句),通常应在break语句的位置添加注释。示例:switch(condition){caseABC:statements;/*fallsthrough*/caseDEF:statements;break;caseXYZ:statements;break;default:statements;break;}try-catch/try-catch-finally语句对于不管try代码块是否成功执行,都必须执行的语句(例如关闭Socket连接),将其放到finally代码块中。示例://没有finally代码块的示例try{statements;}catch(ExceptionClasse){statements;}//有finally代码块的示例try{statements;}catch(ExceptionClasse){statements;}finally{statements;}空白代码中适当使用空白能够有效地增加代码的可理解性。空行空行将逻辑相关的代码段分隔开,以提高可读性。下列情况应该总是使用两个空行:一个源文件的两个片段(section)之间类声明和接口声明之间下列情况应该总是使用一个空行:两个方法之间一个方法内的两个逻辑段之间,用以提高可读性空格下列情况应该使用空格:一个紧跟着括号的关键字应该被空格分开,例如:while(true){...}注意:空格不应该置于方法名与其左括号之间。这将有助于区分关键字和方法调用空白应该位于参数列表中逗号的后面。所有的二元运算符,除了".",应该使用空格将之与操作数分开。一元操作符和操作数之间不因该加空格,比如:负号("-")、自增("++")和自减("--")。for语句中的表达式应该被空格分开。强制转型后应该跟一个空格。设计类和方法创建具有很强内聚力的类方法的重要性往往比类的重要性更容易理解,方法是指执行一个统一函数的一段代码。类常被错误的视为是一个仅仅用于存放方法的容器。有些开发人员甚至把这种思路作了进一步的发挥,将他们的所有方法放入单个类之中。之所以不能正确的认识类的功能,原因之一是类的实现实际上并不影响程序的执行。当一个工程被编译时,如果所有方法都放在单个类中或者放在几十个类中,这没有任何关系。虽然类的数量对代码的执行并无太大的影响,但是当创建便于调试和维护的代码时,类的数量有时会带来很大的影响。类应该用来将相关的方法组织在一起。当类包含一组紧密关联的方法时,该类可以说具有强大的内聚力。当类包含许多互不相关的方法时,该类便具有较弱的内聚力。应该努力创建内聚力比较强的类。大多数工程都包含许多并不十分适合与其他方法组合在一起的方法。在这种情况下,可以为这些不合群的方法创建一个综合性收容类。创建类时,应知道“模块化”这个术语的含义是什么。类的基本目的是创建相当独立的程序单元。创建松散连接和高度专用的方法使所有方法都执行专门的任务每个方法都应执行一项特定的任务,它应出色的完成这项任务。应避免创建执行许多不同任务的方法。创建专用方法有许多好处,例如调试将变得更加容易。

尽量使方法成为自成一体的独立方法当一个方法依赖于其他方法的调用时,称为与其他方法紧密连接的方法。紧密连接的方法会使调试和修改变得比较困难,因为它牵涉到更多的因素。松散连接的方法优于紧密连接的方法,但你不可能使每个方法都成为独立的方法。若要使方法具备较强的独立性,方法之一是尽量减少类变量。创建方法时,设法将每个方法视为一个黑箱,其他例程不应要求了解该方法的内部工作情况,该方法也不应要求了解它外面的工程情况。这就是为什么你的方法应依靠参数而不应依靠全局变量的原因。创建专用方法时,请考虑下列指导原则:1)

将复杂进程放入专用方法。如果应用程序使用复杂的数学公式,请考虑将每个公式放入它自己的方法中。这样使用这些公式的其他方法就不包含用于该公式的实际代码。这样也可以更容易发现与公式相关的问题。2)

将数据输入/输出(I/O)放入专用方法。3)

将专用方法中可能要修改的代码隔离。如果你知道某个进程经常变更,请将这个多变的代码放入专用方法,以便以后可以更容易的进行修改,并减少无意中给其他进程带来问题的可能性。4)

将业务规则封装在专用方法中。业务规则常属于要修改的代码类别,应与应用程序的其余部分隔开。其他方法不应知道业务规则,只有要调用的方法才使用这些规则。

设计类和方法时,要达到下列目的1)

创建更加容易调试和维护的方法2)

创建具有强大内聚力的类3)

创建高度专用的方法4)

创建松散连接的方法5)

尽量使方法具有独立性6)

提高方法的扇入性7)

降低方法的扇出性编程原则为方法和类赋予表义性强的名字为了使代码更加容易理解,最容易的方法之一是为你的方法赋予表义性强的名字。函数名doIt、getIt的可读性很难与calculateSalesTax、retrieveUserID相比。由缩写方法名组成的代码很难理解和维护,没有理由再这样做了。给方法正确的命名,可使程序工程的调试和维护工作大大的改观。请认真对待方法命名的工作,不要为了减少键入操作量而降低方法的可理解度。实际应用举例:给方法命名时应大小写字母混合使用。如果句子全使用大写字母,那么阅读起来就非常困难,而大小写字母混合使用的句子,阅读起来就很容易。定义方法名时不要使用缩写。如果你认为应用程序中的某些工程应使用缩写,那么请将这些情况加上注释,并确保每个人在所有时间内都使用这些缩写。决不要在某些方法中对某些单词进行缩写,而在别的方法中却不使用缩写。为每个方法赋予单个退出点创建方法时,始终都应显式地定义它的作用域。如果你真的想创建一个公用方法,请向代码阅读者说明这一点。通过为每个方法赋予一个明确定义的作用域,可以减少代码阅读者需要投入的工作量。应确保你为方法赋予最有意义的作用域。如果一个方法只被同一类中的另一个方法调用,那么请将它创建成私有方法。如果该方法是从多个类中的多个方法中调用,请将该说明为公用方法。用参数在方法之间传递数据应尽量避免使用类变量。一般来说,变量的作用域越小越好。为了减少类变量,方法之一是将数据作为参数在不同方法之间传递,而不是让方法共享类变量。为每个参数指定数据类型。始终要对数进行检验,决不要假设你得数据没有问题。很多人常犯的一个错误是在编写方法时假设数据没有问题。在初始编程阶段,当编写调用方法时,这样的假设并无大碍。这时你完全能够知道什么是参数的许可值,并按要求提供这些值。但如果你不对参数的数据进行检验,那么下列情况就会给你带来很大麻烦:另外某个人创建了一个调用方法,但此人不知道允许的值;你在晚些时候添加了新的调用方法,并错误的传递了坏数据。一些编程惯例提供对实例以及类变量的访问控制若没有足够理由,不要把实例或类变量声明为公有。尽量通过方法(比如符合JavaBean规范的getter和setter)来操作实例或类变量。对于一些公用的常量,设置为公有是合适的。引用类变量和类方法避免用一个对象访问一个类的静态变量和方法。应该用类名替代。常量在代码中不应直接硬编码常量,特别是当这个常量具有某些业务意义的时候,应该定义一个合适名称的final变量。例如位于for循环中作为计数器值的数字常量,除了-1,0和1之外,不应被直接写入代码。变量赋值避免在一个语句中给多个变量赋相同的值,它很难读懂。圆括号一般而言,在含有多种运算符的表达式中使用圆括号来避免运算符优先级问题,是个好方法。即使运算符的优先级对你而言可能很清楚,但对其他人未必如此。你不能假设别的程序员和你一样清楚运算符的优先级。内存管理[说明应该如何管理内存。]错误处理和异常事件通常的思想是只对错误采用异常处理:逻辑和编程错误,设置错误,被破坏的数据,资源耗尽,等等。通常的法则是系统在正常状态下以及无重载和硬件失效状态下,不应产生任何异常。错误捕获方式:FATAL级别的例外:直接处理错误,写日志,并抛出一个例外,由上一级调用的类对例外判断,并转换成用户可以理解的信息然后继续向上抛出,直到用户可以直接调用或者访问到为至。其他级别的例外:抛出到上一级调用的类,然后处理错误并写日志,然后将错误信息转换成用户可以理解的信息然后继续向上抛出,直到用户可以直接调用或者访问到为至。释放资源统一在final里面做.错误日志处理:使用APILog4J作为日志的管理工具,日志的优先级约定如下:FATAL级别:当产生的错误会对整个服务导致严重的后果,比如服务器瘫痪,机器死机等等,这时候定义为FATAL级。格式:日志级别(FATAL)+时间(YYYY-MM-DDhh-mm-ss)+类名+函数名+日志代码的行号+错误原因ERROR级别:当产生的错误会使对所有用户或者一批用户都不能提供服务,但是系统并不瘫痪的时候,比如找不到数据库连接Connection,某些数据错误,这时候定义为ERROR级。格式:日志级别(ERROR)+时间(YYYY-MM-DDhh-mm-ss)+类名+函数名+日志代码的行号+错误原因WARN级别:当产生的错误会使对某个用户不能提供服务,但对其他用户无影响时,比如某些数据不符合,这时候定义为WARN级。格式:日志级别(WARN)+时间(YYYY-MM-DDhh-mm-ss)+类名+函数名+日志代码的行号+错误原因INFO级别:当有些信息并不是错误,只是想输出给系统管理者看的时候,比如在一些事务的开始和结束,或者回滚的时候做出标志。格式:日志级别(INFO)+时间(YYYY-MM-DDhh-mm-ss)+类名+函数名+日志代码的行号+信息内容DEBUG级别:当有些信息为调试程序使用,只是在调试阶段想输出给开发人员看的时候,这时候定义为DEBUG级。格式:日志级别(DEBUG)+时间(YYYY-MM-DDhh-mm-ss)+类名+函数名+日志代码的行号+信息内容可移植性尽量不要使用已经被标为不赞成使用的类或方法。如果需要换行的话,尽量用println来代替在字符串中使用"\n"。用separator()方法代替路径中的”/”或”\”。用pathSeptarator()方法代替路径中的”:”或”;”。复用[本节提供可以使复用变得更容易的规则和指南。]涉及到代码质量的问题制造多余代码例如下面的类:packagecom.trisun.m2m.aspects;importorg.apache.log4j.Logger;importjava.text.ParsePosition;importjava.text.SimpleDateFormat;importjava.util.Date;importjava.util.Calendar;/***这个类不应该创建*/@DeprecatedpublicclassGetDateTime{privatestaticLoggerlogInfo=Logger.getLogger(GetDateTime.class);/***用于获取当前系统时间(格式="2008-5-2816:46:12")**@return格式化的日期数据*/publicstaticDategetCurrentTime(){SimpleDateFormatformatter=newSimpleDateFormat("yyyy-MM-ddHH:mm:ss");DatecurrentTime1=newDate();StringdateString=formatter.format(currentTime1);ParsePositionpos=newParsePosition(0);DatecurrentTime2=formatter.parse(dateString,pos);returncurrentTime2;}}这个类曾经被大量调用,用来获得系统当前时间,然后保存到数据库中,到目前为止,有的项目中、仍然有一些零散的类似的代码,这么多代码实际上和“newDate()”完全一致,完全不必要专门写一个函数、甚至一个类出来。更严重的是下面的例子:质量上有缺陷的代码示例1:packagecom.trisun.m2m.aspects;importcom.trisun.m2m.model.*;/***@authorEric*@version1.0*@desciption获取对应实体Bean的关键信息*@since2008*<p/>*这个类有问题,没必要存在!*/@DeprecatedpublicclassGetMainInfo{publicStringgetBusinessOperatorInfo(BusinessOperatorbean){Stringtemp="";if(bean!=null){temp+="OperatorName:"+bean.getOperatorName()+"";temp+="Account:"+bean.getAccount()+"";temp+="status:"+bean.getStatus()+"";temp+="tel:"+bean.getTelphone1()+"";temp+="Address:"+bean.getAddress()+"";}returntemp;}//很多类似方法……}其实很多POJO的toString()方法都被重写了,并且除了起到上面类的作用外,其他到目前为止都没有用,而toString()方法往往是被生成的,已经有非常多的例子说明要用StringBuffer之类的对象来实现。上面的做法,如果方法很少被调用,问题也不严重,但是在日志功能模块中,考虑到系统的在线用户数、服务器的运行时间等,这个问题就不那么小了。示例2:publicStringlist(){Sigarsigar=null;try{StringosName=System.getProperties().getProperty("");StringfilePath=MessageTransferStatisticAction.class.getResource("/").getPath();logI("ComputerInfofilePath:"+filePath);if(osName.indexOf("Windows")!=-1){filePath=filePath.substring(1,filePath.lastIndexOf("/"));filePath=filePath.substring(0,filePath.lastIndexOf("/"));}else{// filePath=filePath.substring(0,filePath.lastIndexOf("/"));// filePath=filePath.substring(0,filePath.lastIndexOf("/"));filePath="/opt";}logI("ComputerInfoosName:"+osName);if(osName.indexOf("Windows")!=-1)filePath=filePath+"/lib/sigar-x86-winnt.dll";elsefilePath=filePath+"/lib/libsigar-amd64-linux.so";logI("ComputerInfofilePath:"+filePath);System.load(filePath);sigar=newSigar();}catch(RuntimeExceptione1){//TODOAuto-generatedcatchblocke1.printStackTrace();}try{XStreamxstream=newXStream();StringosName=System.getProperties().getProperty("");setOs(osName);// System.out// .println("\n******************取得网卡流量数据begin********************\n");String[]netIfs=sigar.getNetInterfaceList();ListnetIfList=newArrayList();for(Stringname:netIfs){NetInterfaceDatanetIfData1=NetInterfaceData.gather(sigar,name);netIfList.add(netIfData1);}xstream.alias("NetInterfaceDatas",List.class);xstream.alias("NetInterfaceData",NetInterfaceData.class);// logI(xstream.toXML(netIfList));document=DocumentHelper.parseText(xstream.toXML(netIfList));ListlistConfig=document.selectNodes("/NetInterfaceDatas/NetInterfaceData/config");ListlistStat=document.selectNodes("/NetInterfaceDatas/NetInterfaceData/stat");for(inti=0;i<listStat.size();i++){ElementeleConfig=(Element)listConfig.get(i);ElementeleStat=(Element)listStat.get(i);setAddress(eleConfig.selectSingleNode("address").getText());setHwaddr(eleConfig.selectSingleNode("hwaddr").getText());setRxBytes(eleStat.selectSingleNode("rxBytes").getText());setRxPackets(eleStat.selectSingleNode("rxPackets").getText());setTxBytes(eleStat.selectSingleNode("txBytes").getText());setTxPackets(eleStat.selectSingleNode("txPackets").getText());break;}// System.out// .println("\n******************取得网卡流量数据end********************\n");// System.out// .println("\n******************取得系统内存的数据begin********************\n");MemoryDatamemData=MemoryData.gather(sigar);xstream.alias("MemData",MemoryData.class);// logI(xstream.toXML(memData));document=DocumentHelper.parseText(xstream.toXML(memData));setTotalMemorySize(document.selectSingleNode("/MemData/mem/ram").getText()+"MB");setUsedMemory(changeDecimal(2,(newDouble(document.selectSingleNode("/MemData/mem/used").getText()).doubleValue())/(newDouble(document.selectSingleNode("/MemData/mem/total").getText()).doubleValue())*100)+"");setSwapMenory(changeDecimal(2,(newDouble(document.selectSingleNode("/MemData/swap/used").getText()).doubleValue())/(newDouble(document.selectSingleNode("/MemData/swap/total").getText()).doubleValue())*100)

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论