版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、 Java项目开发CodeReview常见问题实例分析及指南第一章 综述4第二章 常见问题分类及实例分析42.1 开发规范类4 命名规范4 代码格式72.2 性能影响及系统稳定性102.2.1 Java操作数据库10 数据库SQL开发注意事项14 数据库存储过程编写17 Java编程方面192.3 编程易错误区及系统健壮性21 空指针错误的引发21 格式化数字错误22 字符串越界错误22 没有克隆(clone)返回的对象22 不必要的克隆24 自编代码来拷贝数组25 拷贝错误的数据26 检查new 操作的结果是否为null28 用= 替代.equals28 混淆原子操作和非原子操作29 在ca
2、tch 块中作清除工作30 增加不必要的catch 块31 没有正确实现equals,hashCode,或者clone 等方法312.4 Java编程不良习惯322.4.1 Servlet中获取数据库连接问题32 对于Exception的处理32 有关常量的使用33 静态变量的使用33 未使用的变量33 过于庞大的try块33 最好不要让系统自己进行类型转换362.5 ResourceOne开发框架使用问题36 在普通JavaClass中获得数据库连接362.5.2 Servlet中使用SearchDAO37 程序调试信息37 超长类名:使用R1Studio生成数据访问类的问题37 代码中直接
3、使用JDBC进行数据库操作38 代码的分包问题38 使用DAO操作时直接在Servlet里进行操作392.6 业务逻辑问题39 程序逻辑错误39第一章 综述基础技术资源开发与管理部在颁布六统一管理代码review办法中,从管理的角度对中软国际所有的软件开发项目的程序代码review作了相关的要求,并且推行Jupiter这样的CodeReview协同管理工具来辅助促进和跟踪review的状态和结果。CodeReview的基本手段还是需要技术经理通过人工检查项目成员的代码,来将各种问题扼杀在开发阶段,但是不同经验及技术水平的经理在review同一段代码所发现的问题可能相差比较大,不同的Team可能
4、因此产生的效果也不同。本文从实际项目中抽取了一些项目中常见的Java开发所涉及的问题,进行实例分析,为各技术经理提供靶子和借鉴参考,如果审查者能够有意识地寻找特定的错误,而不是靠漫无目的的浏览代码来发现错误,那么代码审查的效果会事半功倍如能做到举一反三,则意义更大。第二章 常见问题分类及实例分析2.1 开发规范类在六统一规范中颁布的Java开发编码规范和Delphi开发规范,里面都专门对于Java和Delphi语言进行开发的详细规定。下面是对一些基本要求的重申,对于代码review比较基础和关键。2.1.1 命名规范 Java程序 .1 包名Ø具体的示例如
5、下:com.icss下面为平台包。stmacmbas为本项目的根程序包。stmacmbas.base为本项目的开发基础包merce为商业企业程序包stmacmbas.example为示例程序包stmacmbas.industry为工业企业程序包stmacmbas.stma为国家局程序包stmacmbas.util为工具包.2 文件名Ø 文件名由英文单词组成,每个单词的首字母大写,最好不要超过4个单词,如ShipOrder.java。Ø Java文件的文件名要与程序中的public类名相同。Ø Servet文件要以Servlet做为结尾,如AddCom
6、panyServlet.java.3 类名Ø 变量的名字必须用一个小写字母开头。后面的单词用大写字母开头。.4 变量名Ø Class 变量的命名 :变量的名字必须用一个小写字母开头。后面的单词用大写字母开头。 Ø Static Final 变量的命名 :Static Final 变量的名字应该都大写,并且指出完整含义。Ø 用有意义的名字命名变量 。首先,用完整的英语单词或约定俗成的简写命名你的变量(不允许用汉语拼音),如: firstName,zipCodeØ 用复数命名collection类变量。collectio
7、n包括数组,vector等。命名时使用复数: customers ,classmates.5 方法名Ø 方法的名字必须用一个小写字母开头。后面的单词用大写字母开头。Ø 方法的名字要与该方法的用途相关。.6 参数名Ø 参数的命名 :参数的名字必须和变量的命名规范一致。 Ø 方法的参数 :使用有意义的参数命名,如果可能的话,使用和要赋值的字段一样的名字。 增删改程序和页面的调用关系和文件名AddOrderServer, SaveOrderServer, DeleteOrderServlet不需要页面,其他有JSP页面
8、的Servlet要与JSP文件名相对应。OrderDetailServet对应两个JSP文件,EditOrder用于可编辑状态,ShowOrder用于不可编辑状态。AddOrderServlet和SaveOrderServlet的返回页面可以是List页面,也可以是Detail页面,如果当前人已完成所有可进行的操作,则回到List页面,如果未完成,则回到Detail页面。 CSS为不同的部署功能应用建产不同的CSS件,如建三个文件:stama.css, industry.css和commerce.css2.1.2 代码格式 Java程序.1 文件头
9、216; 版权信息 版权信息必须在 java 文件的开头,比如:/* 类名* 日期* 修改记录* Copyright ICSS 2003* All right reserved.*/其他不需要出现在 javadoc 的信息也可以包含在这里。Ø Package/Imports package 行要在 import 行之前,import 中标准的包名要在本地的包名之前,而且按照字母顺序排列。如果 import 行中包含了同一个包中的不同子目录,则应该用 * 来处理。对于import语句,如果某一个包中引用的类不超过三个(包括三个),不允许用import xxx.*;格式。将import的
10、classes归类,按顺序罗列: a. Java标准类(java.*) b. Java扩充类(javax.*) c. 第三方类 d. 你的应用程序的类.2 缩进缩进应该是每行4个空格,不要在源文件中保存Tab字符。 在使用不同的源代码管理工具时Tab字符将因为用户设置的不同而扩展为不同的宽度。.3 注释为保证开发后JAVA DOC的顺利生成,开发人员必须在所有方法,全局变量前加入加上标准JAVA注释。类注释需要包含以下要素:1 方法描述2 参数: param 参数名 说明3 返回值: return 说明4 例外情况:exception 完整类名 说明/* this
11、is a doc sample* param args array of string arguments* return No return value* exception exception No exceptions thrown */.4 页宽页宽应该设置为80字符, 源代码一般不会超过这个宽度, 并导致无法完整显示, 但这一设置也可以灵活调整。 在任何情况下, 超长的语句应该在一个逗号或者一个操作符后折行, 一条语句折行后, 应该比原来的语句再缩进2个字符。 HTML/JSP.1 文件头文件头要写明该文件的用途,及修改记录。如:<!
12、文件名:OrderList.jsp 说明:订单列表 修改记录:2003-08-24,张三,增加一个按钮à.2 缩进HTML标记层次之间的缩进为2个字符,Java代码的缩进为4个字符,文件中不要有Tab符号,都要替换为空格。2.2 性能影响及系统稳定性相关2.2.1 Java操作数据库 Connection数据库连接未关闭 严重级别:严重 1、问题造成的后果数据库连接池中的数据库连接被耗尽,新的获取数据库连接的请求进入等待状态,由于数据库请求来自一个Servlet线程,因此造成请求的Servlet线程进入等待状态。这也会造成Apache的Http服务器的客户
13、端并发连接数打量增加。此时,访问引用的首页面会出现白页现象。需要重新启动WebSphere才能恢复对应用的访问。2、解决的方法Connection conn = null;try /处理业务逻辑 catch(SQLException) e.printstacktrace(); finally /在finally中关闭数据库连接if(conn!=null) try conn.close(); catch(SQLException e) e.printstacktrace(); Statement/ResultSet未关闭问题严重级别:一般 n 问题代码:程序中典型的未关闭Stat
14、ement对象的写法包括为:Connection conn = null;tryconn = super.getConnection(GLOBAL.DATASOURCEJNDI);String sql = “some sql statement like select * from table ”;conn.createStatement().execute(sql); catch(SQLException) e.printstacktrace(); finally /在finally中关闭数据库连接if(conn!=null) try conn.close(); catch(SQLExcep
15、tion e) e.printstacktrace(); Statement对象未关闭积累到一定程度会造成执行SQL语句时抛出SQLExceptionn 解决方法:首先要在try程序段中获取Statement对象,这需要在try段外声明Statement对象,然后在finally程序段中关闭获取的Statement对象。Connection conn = null;Statement stmt = null;try stmt = conn.createStatement();/处理业务逻辑 catch(SQLException) e.printstacktrace(); finally /在f
16、inally中关闭Statement对象if(stmt!=null) try stmt.close(); catch(SQLException e) e.printstacktrace(); if(conn!=null) try conn.close(); catch(SQLException e) e.printstacktrace(); 类似的问题在PreparedStatement对象和ResultSet对象上也都存在,都需要在调用结束后关闭获取的资源。 数据库事务的使用严重级别:严重 n 问题代码:tryOURCEJNDI); /TCCClientinterralsetD
17、AO TCCClientinterralsetDAO tCCClientinterralsetDAO = new TCCClientinterralsetDAO(); tCCClientinterralsetDAO.setSerialnum(serialnum); tCCClientinterralsetDAO.setIntName(intName); tCCClientinterralsetDAO.setIntegral(Float.valueOf(integral); tCCClientinterralsetDAO.setNote(note); tCCClientinterralsetDA
18、O.create(); /TCCClientvalueinfoMonthDAOTCCClientvalueinfoMonthDAO tCCClientvalueinfoMonthDAO = new TCCClientvalueinfoMonthDAO(); tCCClientvalueinfoMonthDAO.setClientCode(clientCode); tCCClientvalueinfoMonthDAO.setBursarMonth(bursarMonth); tCCClientvalueinfoMonthDAO.setHApprScore(hApprScore); tCCClie
19、ntvalueinfoMonthDAO.setHApprGrade(hApprGrade); tCCClientvalueinfoMonthDAO.create();catch(Exception e) Debug.debug(e.getMessage(),e);n 正确做法:逻辑上对于批量业务的处理,会设计到多个数据库表的操作,当需要保证一次业务的完整性时,应当引入事务处理机制。即首先将Connnection的autoCommit属性设置为false(默认为true),保证全部业务执行成功后,再调用Connection的commit()方法一次提交;如果中途出现异常,则调用Connectio
20、n的rollback()方法进行回滚。 超长事务和死锁严重级别:严重 n 问题代码try conn = getConnection(com.icss.j2ee.util.Globals.DATASOURCEJNDI); DAOFactory factory = new DAOFactory(conn); conn.setAutoCommit(false); String appuuid = request.getParameter("appuuid"); String appname = request.getParameter("appname&q
21、uot;); String cnName = request.getParameter("cnName"); String enName = request.getParameter("enName"); String adminflag = request.getParameter("adminflag"); String enabled = "0" if(request.getParameter("enabled") != null) enabled = request.getParamet
22、er("enabled"); String needRight = "0" if(request.getParameter("needRight") != null) needRight = request.getParameter("needRight"); String navUrl = request.getParameter("navUrl"); String leftFrameEnabled = request.getParameter("leftFrameEnabled&q
23、uot;); String developer = request.getParameter("developer"); String memo = request.getParameter("memo"); String serialindex = "0" if(request.getParameter("serialindex") != null) serialindex = request.getParameter("serialindex"); String leftfirst = re
24、quest.getParameter("leftfirst"); String helpurl = request.getParameter("helpurl");String _page_num = ParamUtils.getParameter(request, "_page_num"); ModuleDAO mdao = new ModuleDAO(); mdao.setConnection(conn); mdao.setMuuid(new com.icss.j2ee.util.UUID().toString(); mdao.s
25、etCnname(cnName); mdao.setEnname(enName); DAOFactory factory = new DAOFactory(conn); Factory.setDAO(mdao); factory.find(); .n 正确做法在程序中使用事务对数据库操作进行加锁,一定要注意尽量缩短事务段的时间,否则会引起系统性能下降甚至导致数据库死锁。事务段内的操作只应该是进行事务保护的相关数据操作的代码,涉及查询及其他无关的代码都应当剥离出去。刚才这段代码的conn.setAutoCommit(false);语句应当往后放,只在事务保护的数据操作开始之前,并且在数据操作完成
26、后立即进行事务提交mit()来尽早释放数据库锁。2.2.2 数据库SQL开发注意事项 IS NULL 与 IS NOT NULL 不能用null作索引,任何包含null值的列都将不会被包含在索引中。即使索引有多列这样的情况下,只要这些列中有一列含有null,该列就会从索引中排除。也就是说如果某列存在空值,即使对该列建索引也不会提高性能。 任何在where子句中使用is null或is not null的语句优化器是不允许使用索引的。 联接列 对于有联接的列,即使最后的联接值为一个静态值,优化器是不会使用索引的。例如:假定有一个职工表(employee),对于一个职
27、工的姓和名分成两列存放(FIRST_NAME和LAST_NAME),现在要查询一个叫比尔.克林顿(Bill Cliton)的职工。 下面是一个采用联接查询的SQL语句, select * from employss where first_name|''|last_name ='Beill Cliton' 上面这条语句完全可以查询出是否有Bill Cliton这个员工,但是这里需要注意,系统优化器对基于last_name创建的索引没有使用。 当采用下面这种SQL语句的编写,在Oracle系统中就可以采用基于last_name创建的索引。 Select * fro
28、m employee where first_name ='Beill' and last_name ='Cliton' 遇到下面这种情况又如何处理呢?如果一个变量(name)中存放着Bill Cliton这个员工的姓名,对于这种情况又如何避免全程遍历,使用索引呢?可以使用一个函数,将变量name中的姓和名分开就可以了,但是有一点需要注意,这个函数是不能作用在索引列上。下面是SQL查询脚本: select * from employee where first_name = SUBSTR('&&name',1,INSTR('
29、;&&name',' ')-1) and last_name = SUBSTR('&&name',INSTR('&&name,' ')+1) 带通配符(%)的like语句 同样以上面的例子来看这种情况。目前的需求是这样的,要求在职工表中查询名字中包含cliton的人。可以采用如下的查询SQL语句: select * from employee where last_name like '%cliton%' 这里由于通配符(%)在搜寻词首出现,在Orac
30、le系统不使用last_name的索引。在很多情况下可能无法避免这种情况,但是一定要心中有底,通配符如此使用会降低查询速度。然而当通配符出现在字符串其他位置时,优化器就能利用索引。在下面的查询中索引得到了使用: select * from employee where last_name like 'c%' Order by语句 ORDER BY语句决定了如何将返回的查询结果排序。Order by语句对要排序的列没有什么特别的限制,也可以将函数加入列中(象联接或者附加等)。任何在Order by语句的非索引项或者有计算表达式都将降低查询速度。 仔细检查order
31、 by语句以找出非索引项或者表达式,它们会降低性能。解决这个问题的办法就是重写order by语句以使用索引,也可以为所使用的列建立另外一个索引,同时应绝对避免在order by子句中使用表达式。 NOT 我们在查询时经常在where子句使用一些逻辑表达式,如大于、小于、等于以及不等于等等,也可以使用and(与)、or(或)以及not(非)。NOT可用来对任何逻辑运算符号取反。下面是一个NOT子句的例子: . where not (status ='VALID') 如果要使用NOT,则应在取反的短语前面加上括号,并在短语前面加上NOT运算符。NOT运算符包含在另
32、外一个逻辑运算符中,这就是不等于(<>)运算符。换句话说,即使不在查询where子句中显式地加入NOT词,NOT仍在运算符中,见下例: . where status <>'INVALID' 再看下面这个例子: select * from employee where salary<>3000; 对这个查询,可以改写为不使用NOT: select * from employee where salary<3000 or salary>3000; 虽然这两种查询的结果一样,但是第二种查询方案会比第一种查询方案更快些。第二种查询允许对s
33、alary列使用索引,而第一种查询则不能使用索引。 IN和EXISTS 有时候会将一列和一系列值相比较。最简单的办法就是在where子句中使用子查询。在where子句中可以使用两种格式的子查询。 第一种格式是使用IN操作符: . where column in(select * from . where .); 第二种格式是使用EXIST操作符: . where exists (select 'X' from .where .); 相信绝大多数人会使用第一种格式,因为它比较容易编写,而实际上第二种格式要远比第一种格式的效率高。在常见数据库中可以几乎将所有的IN操
34、作符子查询改写为使用EXISTS的子查询。 第二种格式中,子查询以select 'X'开始。运用EXISTS子句不管子查询从表中抽取什么数据它只查看where子句。这样优化器就不必遍历整个表而仅根据索引就可完成工作(这里假定在where语句中使用的列存在索引)。相对于IN子句来说,EXISTS使用相连子查询,构造起来要比IN子查询困难一些。 通过使用EXIST,数据库系统会首先检查主查询,然后运行子查询直到它找到第一个匹配项,这就节省了时间。在执行IN子查询时,首先执行子查询,并将获得的结果列表存放在在一个加了索引的临时表中。在执行子查询之前,系统先将主查询挂起,待子查询执行完
35、毕,存放在临时表中以后再执行主查询。这也就是使用EXISTS比使用IN通常查询速度快的原因。 同时应尽可能使用NOT EXISTS来代替NOT IN,尽管二者都使用了NOT(不能使用索引而降低速度),NOT EXISTS要比NOT IN查询效率更高。2.2.3 数据库存储过程编写 建立本库视图开发人员如果用到其他库的Table或View,务必在当前库中建立View来实现跨库操作,最好不要直接使用“databse.dbo.table_name”,因为sp_depends不能显示出该SP所使用的跨库table或view,不方便校验。 存储过程中SQL的使用1、 尽量避免
36、大事务操作,慎用holdlock子句,提高系统并发能力。2、 尽量避免反复访问同一张或几张表,尤其是数据量较大的表,可以考虑先根据条件提取数据到临时表中,然后再做连接。 3、 尽量避免使用游标,因为游标的效率较差,如果游标操作的数据超过1万行,那么就应该改写;如果使用了游标,就要尽量避免在游标循环中再进行表连接的操作。 4、 注意where字句写法,必须考虑语句顺序,应该根据索引顺序、范围大小来确定条件子句的前后顺序,尽可能的让字段顺序与索引顺序相一致,范围从大到小。 5、 不要在where子句中的“=”左边进行函数、算术运算或其他表达式运算,否则系统将可能无法正确使用索引。 6、 尽量使用e
37、xists代替select count(1)来判断是否存在记录,count函数只有在统计表中所有行数时使用,而且count(1)比count(*)更有效率。 7、 尽量使用“>=”,不要使用“>”。 8、 注意一些or子句和union子句之间的替换 9、 注意表之间连接的数据类型,避免不同类型数据之间的连接。 10、 注意存储过程中参数和数据类型的关系。 11、 注意insert、update操作的数据量,防止与其他应用冲突。如果数据量超过200个数据页面(400k),那么系统将会进行锁升级,页级锁会升级成表级锁。 索引的使用 1、 索引的创建要与应用结合考虑,建议
38、大的OLTP表不要超过6个索引。 2、 尽可能的使用索引字段作为查询条件,尤其是聚簇索引,必要时可以通过index index_name来强制指定索引 3、 避免对大表查询时进行table scan,必要时考虑新建索引。 4、 在使用索引字段作为条件时,如果该索引是联合索引,那么必须使用到该索引中的第一个字段作为条件时才能保证系统使用该索引,否则该索引将不会被使用。 5、 要注意索引的维护,周期性重建索引,重新编译存储过程。 tempdb的使用1、 尽量避免使用distinct、order by、group by、having、join、cumpute,因为这些语句会加重tem
39、pdb的负担。 2、 避免频繁创建和删除临时表,减少系统表资源的消耗。 3、 在新建临时表时,如果一次性插入数据量很大,那么可以使用select into代替create table,避免log,提高速度;如果数据量不大,为了缓和系统表的资源,建议先create table,然后insert。 4、 如果临时表的数据量较大,需要建立索引,那么应该将创建临时表和建立索引的过程放在单独一个子存储过程中,这样才能保证系统能够很好的使用到该临时表的索引。 5、 如果使用到了临时表,在存储过程的最后务必将所有的临时表显式删除,先truncate table,然后drop table,这样可以避免系统表的
40、较长时间锁定。 6、 慎用大的临时表与其他大表的连接查询和修改,减低系统表负担,因为这种操作会在一条语句中多次使用tempdb的系统表。 合理的算法使用: 结合实际应用,采用多种算法进行比较,以获得消耗资源最少、效率最高的方法。具体可用ASE调优命令:set statistics io on, set statistics time on , set showplan on 等。2.2.4 Java编程方面 InputStream/OutputStream未关闭问题严重级别:严重1、问题造成的后果对文件对象构造的InputStream/OutputStream对象
41、未关闭会造成在同一段程序中调用File.delete()方法删除同一个文件时删除失败的情况。2、解决的方法在对InputStream/OutputStream对象使用完毕后需要显式的关闭流对象。为了防止在程序执行过程中出现异常造成流对象无法关闭的情况,也可以在finally段中关闭流对象。 资源使用完成的释放方式严重级别:严重n 问题代码:String fileFullName = getUploadFileFullName(request, "imageurl");File imagfile=new File(fileFullName);imagefileI
42、nputstream = new FileInputStream(fileFullName);String sql ="Select max(SERIAL) SERIAL from T_M_C_LICENCEANNEX where APPLYCODE ='"+code+"'"if(conn!=null) stmt = conn.createStatement();if(stmt!=null) rs = stmt.executeQuery(sql); try conn= getConnection(DBUtil.DS_JNDI);TCCEx
43、ameinfoHeadDAO tCCExameinfoHeadDAO = new TCCExameinfoHeadDAO();tCCExameinfoHeadDAO.setSerialnum(serialnum);tCCExameinfoHeadDAO.setTargetValue(targetValue);TCCExameinfoHeadHandler tCCExameinfoHeadHandler = new TCCExameinfoHeadHandler(conn);tCCExameinfoHeadHandler.update(tCCExameinfoHeadDAO,true); cat
44、ch (ServiceLocatorException e) / TODO 自动生成 catch 块e.printStackTrace(); catch (DAOException e) / TODO 自动生成 catch 块e.printStackTrace();n 正确做法:第一种情况,在各种Stream对象使用完毕后,应当显式的进行关闭,释放资源;第二种情况,应当在 Statement和ResultSet用完后,在finally代码块中显式的关闭资源。 多次拷贝字符串严重级别:普通通常测试所不能发现的一个错误是生成不可变(immutable)对象的多份拷贝。不可变对象是不可
45、改变的,因此不需要拷贝它。最常用的不可变对象是String。如果你必须改变一个String对象的内容,你应该使用StringBuffer。下面的代码会正常工作: String s = new String ("Text here"); 但是,这段代码性能差,而且没有必要这么复杂。你还可以用以下的方式来重写上面的代码: String temp = "Text here" String s = new String (temp); 但是这段代码包含额外的String,并非完全必要。更好的代码为: String s = "Text here"
46、; 第三种情况,应当在数据链接用完后,在finally代码块中显式的关闭。 避免太多的使用 synchronized 关键字 严重级别:严重避免不必要的使用关键字 synchronized,应该在必要的时候再使用她,这是一个避免死锁的好方法。 字符串操作尽量使用 StringBuffer 对象严重级别:低在处理 String 的时候要尽量使用 StringBuffer 类,StringBuffer 类是构成 String 类的基础。String 类将 StringBuffer 类封装了起来,(以花费更多时间为代价)为开发人员提供了一个安全的接口。当我们在构造字符串
47、的时候,我们应该用 StringBuffer 来实现大部分的工作,当工作完成后将 StringBuffer 对象再转换为需要的 String 对象。比如:如果有一个字符串必须不断地在其后添加许多字符来完成构造,那么我们应该使用 StringBuffer 对象和她的 append() 方法。如果我们用 String 对象代替 StringBuffer 对象的话,会花费许多不必要的创建和释放对象的 CPU 时间。2.3 编程易错误区及系统健壮性2.3.1 空指针错误的引发严重级别:严重n 问题代码:out.println(request.getParameter("username&qu
48、ot;);n 正确做法:使用基本的JAVA数据类型,变量的值要么已经是默认值,如果没有对其正常赋值,程序便不能通过编译,因此使用基本的JAVA数据类型(double,float,boolean,char,int,long)一般不会引起空指针异常。由此可见,空指针异常主要跟与对象的操作相关。看上去,上面的语句找不出什么语法错误,而且在大多数情况下也遇不到什么问题。但是,如果某个用户在输入数据时并没有提供表单域"username"的值,或通过某种途径绕过表单直接输入时,此时request.getParameter("username")的值为空(不是空字符串
49、,是空对象null),out对象的println方法是无法直接对空对象操作,因此将会抛出java.lang.NullPointerException异常。2.3.2 格式化数字错误严重级别:普通n 问题代码:String s_memberid = request.getParameter("memberid"); int i_memberid = Integer.parseInt(s_memberid);n 正确做法:如果用户输入正确的数字如:1082,不会有什么问题。然而,如果用户输入T1082时,由于T1082不是合法的数字格式,Java无法将其转化为合适的数字,导致抛
50、出java.lang.NumberFormatException数字格式化异常。在任何用到字符串转化为数字时,捕捉异常,对异常情况进行处理。这样,在编程时稍微麻烦一点,但可以保证模块更加健壮。2.3.3 字符串越界错误严重级别:普通n 问题代码:String s_all_power = "1010011" tring s_access_power = s_all_power.substring(3,4);n 正确做法:一般情况下,程序不会有问题,如果由于某种原因,s_all_power长度变短,程序就会抛出字符串错误。所以,对字符串进行截取(substring, charA
51、t)、转换为字节数组(getBytes)、字符数组转换为字符串(valueOf)等操作时,应当先对操作字符串对象的存在性(是否为空)及长度进行检查后,再进行操作。2.3.4 没有克隆(clone)返回的对象严重级别:普通封装(encapsulation)是面向对象编程的重要概念。不幸的是,Java为不小心打破封装提供了方便Java允许返回私有数据的引用(reference)。下面的代码揭示了这一点: imension; /*Example class.The x and y values should never*be negative.*/ public class Example priv
52、ate Dimension d = new Dimension (0, 0); public Example () /* Set height and width. Both height and width must be nonnegative * or an exception is thrown.*/ public synchronized void setValues (int height,int width) throws IllegalArgumentException if (height < 0 | width < 0) throw new IllegalArg
53、umentException(); d.height = height; d.width = width; public synchronized Dimension getValues() / Ooops! Breaks encapsulation return d; Example类保证了它所存储的height和width值永远非负数,试图使用setValues()方法来设置负值会触发异常。不幸的是,由于getValues()返回d的引用,而不是d的拷贝,你可以编写如下的破坏性代码: Example ex = new Example(); Dimension d = ex.getValue
54、s(); d.height = -5; d.width = -10; 现在,Example对象拥有负值了!如果getValues() 的调用者永远也不设置返回的Dimension对象的width 和height值,那么仅凭测试是不可能检测到这类的错误。不幸的是,随着时间的推移,客户代码可能会改变返回的Dimension对象的值,这个时候,追寻错误的根源是件枯燥且费时的事情,尤其是在多线程环境中。更好的方式是让getValues()返回拷贝: public synchronized Dimension getValues() return new Dimension (d.x, d.y); 现在,Example对象的内部状态就安全了。调用者可以根据需要改变它所得到的拷贝的状态,但是要修改Example对象的内部状态,必须通过setValues()才可以。2.3.5 不必要的克隆严重级别:普通我们现在知道了get方法应该返回内部数据对象的拷贝,而不是引用。但是,事情没有绝对: /* Example class.The value should never * be negative.*/ public class Example private Integer i = new Integer (0); public Example () /* Set x. x must be n
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 全麻术后并发症及护理措施
- 泵车进退场流程控制措施
- 耐用持久质量承诺承诺书7篇
- 信息安全防护举措承诺书7篇
- 线上学习交流互动研讨会方案
- 2026年农业科技竞赛实操理论试题及答案
- 2026年制造业与新一代信息技术融合知识竞赛
- 2026年高压试验现场围栏设置与放电接地问答
- 2026年新时代高校思想政治理论课教学工作基本要求练习题
- 2026年秋招面试常见问题及应对策略
- 2022年河北雄安新区容西片区综合执法辅助人员招聘考试真题
- 周围血管与淋巴管疾病第九版课件
- 付款计划及承诺协议书
- 王君《我的叔叔于勒》课堂教学实录
- CTQ品质管控计划表格教学课件
- 沙库巴曲缬沙坦钠说明书(诺欣妥)说明书2017
- GB/T 42449-2023系统与软件工程功能规模测量IFPUG方法
- GB/T 5781-2000六角头螺栓全螺纹C级
- 卓越绩效管理模式的解读课件
- 枇杷病虫害的防治-课件
- 疫苗及其制备技术课件
评论
0/150
提交评论