|
马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有帐号?立即注册
x
IDE是好。java中的IDE更是百花齐放,你用jbuilder能说jbuilder赶不上vs吗?用eclipse,netbeans也很舒服啊。我就不明白“稍微差一些”那一些是从哪里差来的。非常处置你以为本人是一个Java专家吗?是不是一定本人已周全把握了Java的非常处置机制?鄙人面这段代码中,你可以敏捷找出非常处置的六个成绩吗?
1OutputStreamWriterout=...
2java.sql.Connectionconn=...
3try{//⑸
4 Statementstat=conn.createStatement();
5 ResultSetrs=stat.executeQuery(
6 "selectuid,namefromuser");
7 while(rs.next())
8 {
9 out.println("ID:"+rs.getString("uid")//⑹
10 ",姓名:"+rs.getString("name"));
11 }
12 conn.close();//⑶
13 out.close();
14}
15catch(Exceptionex)//⑵
16{
17 ex.printStackTrace();//⑴,⑷
18}
作为一个Java程序员,你最少应当可以找出两个成绩。可是,假如你不克不及找出全体六个成绩,请持续浏览本文。
本文会商的不是Java非常处置的一样平常性准绳,由于这些准绳已被年夜多半人熟知。我们要做的是剖析各类可称为“反例”(anti-pattern)的违反优异编码标准的罕见坏习气,匡助读者熟习这些典范的不和例子,从而可以在实践事情中灵敏地发觉和制止这些成绩。
反例之一:抛弃非常
代码:15行-18行。
这段代码捕捉了非常却不作任那边理,能够算得上Java编程中的杀手。从成绩呈现的频仍水平和祸患水平来看,它大概能够和C/C++程序的一个恶名远播的成绩等量齐观??不反省缓冲区是不是已满。假如你看到了这类抛弃(而不是抛出)非常的情形,能够百分之九十九地一定代码存在成绩(在少少数情形下,这段代码有存在的来由,但最好加上完全的正文,以避免引发他人曲解)。
这段代码的毛病在于,非常(几近)老是意味着某些事变不合错误劲了,大概说最少产生了某些不平常的事变,我们不该该对程序收回的求救旌旗灯号坚持缄默和无动于中。挪用一下printStackTrace算不上“处置非常”。不错,挪用printStackTrace对换试程序有匡助,但程序调试阶段停止以后,printStackTrace就不该再在非常处置模块中担当次要义务了。
抛弃非常的情况十分广泛。翻开JDK的ThreadDeath类的文档,能够看到上面这段申明:“出格地,固然呈现ThreadDeath是一种‘一般的情况’,但ThreadDeath类是Error而不是Exception的子类,由于很多使用会捕捉一切的Exception然后抛弃它不再理会。”这段话的意义是,固然ThreadDeath代表的是一种一般的成绩,但鉴于很多使用会试图捕捉一切非常然后不予以得当的处置,以是JDK把ThreadDeath界说成了Error的子类,由于Error类代表的是一样平常的使用不该该往捕捉的严峻成绩。可见,抛弃非常这一坏习气是云云罕见,它乃至已影响到了Java自己的计划。
那末,应当如何更正呢?次要有四个选择:
1、处置非常。针对该非常接纳一些举动,比方修改成绩、提示某团体或举行其他一些处置,要依据详细的情况断定应当接纳的举措。再次申明,挪用printStackTrace算不上已“处置好了非常”。
2、从头抛出非常。处置非常的代码在剖析非常以后,以为本人不克不及处置它,从头抛出非常也不掉为一种选择。
3、把该非常转换成另外一种非常。年夜多半情形下,这是指把一个初级的非常转换成使用级的非常(其寄义更简单被用户懂得的非常)。
4、不要捕捉非常。
结论一:既然捕捉了非常,就要对它举行得当的处置。不要捕捉非常以后又把它抛弃,不予理会。
反例之二:不指定详细的非常
代码:15行。
很多时分人们会被如许一种“美好的”设法吸引:用一个catch语句捕捉一切的非常。最多见的情况就是利用catch(Exceptionex)语句。但实践上,在尽年夜多半情形下,这类做法不值得倡始。为何呢?
要了解其缘故原由,我们必需回忆一下catch语句的用处。catch语句暗示我们预期会呈现某种非常,并且但愿可以处置该非常。非常类的感化就是告知Java编译器我们想要处置的是哪种非常。因为尽年夜多半非常都间接或直接从java.lang.Exception派生,catch(Exceptionex)就相称于说我们想要处置几近一切的非常。
再来看看后面的代码例子。我们真正想要捕捉的非常是甚么呢?最分明的一个是SQLException,这是JDBC操纵中罕见的非常。另外一个大概的非常是IOException,由于它要操纵OutputStreamWriter。明显,在统一个catch块中处置这两种一模一样的非常是分歧适的。假如用两个catch块分离捕捉SQLException和IOException就要很多多少了。这就是说,catch语句应该只管指定详细的非常范例,而不该该指定涵盖局限太广的Exception类。
另外一方面,除这两个特定的非常,另有其他很多非常也大概呈现。比方,假如因为某种缘故原由,executeQuery前往了null,该怎样办?谜底是让它们持续抛出,即不用捕捉也不用处置。实践上,我们不克不及也不该该往捕捉大概呈现的一切非常,程序的其他中央另有捕捉非常的时机??直至最初由JVM处置。
结论二:在catch语句中尽量指定详细的非常范例,需要时利用多个catch。不要试图处置一切大概呈现的非常。
反例之三:占用资本不开释
代码:3行-14行。
非常改动了程序一般的实行流程。这个事理固然复杂,却经常被人们无视。假如程序用到了文件、Socket、JDBC毗连之类的资本,即便碰到了非常,也要准确开释占用的资本。为此,Java供应了一个简化这类操纵的关头词finally。
finally是样好工具:不论是否呈现了非常,Finally包管在try/catch/finally块停止之前,实行清算义务的代码老是无机会实行。遗憾的是有些人却不习气利用finally。
固然,编写finally块应该多加当心,出格是要注重在finally块以内抛出的非常??这是实行清算义务的最初时机,只管不要再有难以处置的毛病。
结论三:包管一切资本都被准确开释。充实使用finally关头词。
反例之四:不申明非常的具体信息
代码:3行-18行。
细心察看这段代码:假如轮回外部呈现了非常,会产生甚么事变?我们能够失掉充足的信息判别轮回外部堕落的缘故原由吗?不克不及。我们只能晓得以后正在处置的类产生了某种毛病,但却不克不及取得任何信息判别招致以后毛病的缘故原由。
printStackTrace的仓库跟踪功效显现出程序运转到以后类的实行流程,但只供应了一些最基础的信息,未能申明实践招致毛病的缘故原由,同时也不容易解读。
因而,在呈现非常时,最好可以供应一些笔墨信息,比方以后正在实行的类、办法和其他形态信息,包含以一种更合适浏览的体例收拾和构造printStackTrace供应的信息。
结论四:在非常处置模块中供应过量的毛病缘故原由信息,构造毛病信息使其易于了解和浏览。
反例之五:过于复杂的try块
代码:3行-14行。
常常能够看到有人把大批的代码放进单个try块,实践上这不是好习气。这类征象之以是罕见,缘故原由就在于有些人图费事,不肯花工夫剖析一年夜块代码中哪几行代码会抛出非常、非常的详细范例是甚么。把大批的语句装进单个伟大的try块就象是出门旅游时把一切一样平常用品塞进一个年夜箱子,固然工具是带上了,但要找出来可不简单。
一些老手经常把大批的代码放进单个try块,然后再在catch语句中声明Exception,而不是分别各个大概呈现非常的段落并分离捕捉其非常。这类做法为剖析程序抛出非常的缘故原由带来了坚苦,由于一年夜段代码中有太多的中央大概抛出Exception。
结论五:只管减小try块的体积。
反例之六:输入数据不完全
代码:7行-11行。
不完全的数据是Java程序的隐形杀手。细心察看这段代码,思索一下假如轮回的两头抛出了非常,会产生甚么事变。轮回的实行固然是要被打断的,其次,catch块会实行??就这些,再也没有其他举措了。已输入的数据怎样办?利用这些数据的人或设备将收到一份不完全的(因此也是毛病的)数据,却得不就任何有关这份数据是不是完全的提醒。关于有些体系来讲,数据不完全大概比体系中断运转带来更年夜的丧失。
较为幻想的处理举措是向输入设备写一些信息,声明数据的不完全性;另外一种大概无效的举措是,先缓冲要输入的数据,筹办好全体数据以后再一次性输入。
结论六:周全思索大概呈现的非常和这些非常对实行流程的影响。
改写后的代码
依据下面的会商,上面给出改写后的代码。大概有人会说它略微有点?嗦,可是它有了对照完整的非常处置机制。
OutputStreamWriterout=...
java.sql.Connectionconn=...
try{
Statementstat=conn.createStatement();
ResultSetrs=stat.executeQuery(
"selectuid,namefromuser");
while(rs.next())
{
out.println("ID:"+rs.getString("uid")+",姓名:"+rs.getString("name"));
}
}
catch(SQLExceptionsqlex)
{
out.println("告诫:数据不完全");
thrownewApplicationException("读取数据时呈现SQL毛病",sqlex);
}
catch(IOExceptionioex)
{
thrownewApplicationException("写进数据时呈现IO毛病",ioex);
}
finally
{
if(conn!=null){
try{
conn.close();
}
catch(SQLExceptionsqlex2)
{
System.err(this.getClass().getName()+".mymethod-不克不及封闭数据库毗连:"+sqlex2.toString());
}
}
if(out!=null){
try{
out.close();
}
catch(IOExceptionioex2)
{
System.err(this.getClass().getName()+".mymethod-不克不及封闭输入文件"+ioex2.toString());
}
}
}
本文的结论不是放之四海皆准的教条,偶然知识和履历才是最好的先生。假如你对本人的做法没有百分之百的信念,务必加上具体、周全的正文。
另外一方面,不要笑话这些毛病,无妨问问你本人是不是真地完全挣脱了这些坏习气。即便最有履历的程序员偶然也会迷途知返,缘故原由很复杂,由于它们确的确实带来了“便利”。一切这些反例都能够看做Java编程天下的恶魔,它们俊丽动听,无孔不进,时候勾引着你。大概有人会以为这些都属于鸡皮蒜毛的大事,不足齿数,但请记着:勿以恶小而为之,勿以善小而不为。
因为能用到多少功能就用多少,不能用就不用!总的来说:要简单要性能好,可以不用框架。你说java复杂,就是因为你把java(j2ee)与这些框架混在了一起。 |
|