﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-浪花一朵朵-随笔分类-J2SE</title><link>http://www.blogjava.net/huabingl/category/11664.html</link><description>读万篇贴，想千百回，落十几字</description><language>zh-cn</language><lastBuildDate>Tue, 27 Feb 2007 12:18:11 GMT</lastBuildDate><pubDate>Tue, 27 Feb 2007 12:18:11 GMT</pubDate><ttl>60</ttl><item><title>一个简单的ThreadPool分析</title><link>http://www.blogjava.net/huabingl/archive/2006/07/16/58451.html</link><dc:creator>binge</dc:creator><author>binge</author><pubDate>Sun, 16 Jul 2006 12:07:00 GMT</pubDate><guid>http://www.blogjava.net/huabingl/archive/2006/07/16/58451.html</guid><wfw:comment>http://www.blogjava.net/huabingl/comments/58451.html</wfw:comment><comments>http://www.blogjava.net/huabingl/archive/2006/07/16/58451.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/huabingl/comments/commentRss/58451.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/huabingl/services/trackbacks/58451.html</trackback:ping><description><![CDATA[一个简单的ThreadPool<br />  原文来自<a href="http://www.informit.com/articles/printerfriendly.asp?p=30483&amp;r1=1&amp;rl=1">http://www.informit.com/articles/printerfriendly.asp?p=30483&amp;r1=1&amp;rl=1</a><br />  项目是多线程的，所以引入了线程池这个东西。池子是个老美写的。在项目中表现的还不错。所以把它摘出来，介绍给以后或许需要用到它的同行们。<br />  关于为什么要采用ThreadPool，原文已经提到了：创建一个线程是需要开销的;如果线程数量过大的话，cpu就会浪费很大的精力做线程切换。<br />  ThreadPool的实现过程就是对WorkerThread的同步和通信的管理过程。<br />  我们来看代码。<br />  首先，在ThreadPool构造的时候，创建10个WorkerThread（size=10）并让他们运行。每个WorkerThread线程都有个ThreadPool的引用,用于查询ThreadPool的状态和获得同步锁.WorkerThread运行以后,循环调用ThreadPool的方法进行查询,如果没有发现任务,ThreadPool告诉正在查询的线程进入休眠状态,WorkerThread释放对查询方法的锁定.这样在还没有任务的时候,所有的10个WorkerThread都会进入休眠状态,进入等待ThreadPool对象的等待锁定池，只有ThreadPool对象发出notify方法（或notifyAll）后WorkerThread线程才进入对象锁定池准备获得对象锁进入运行状态。<br />代码片断:<br />while ( !assignments.iterator().hasNext() )<br />    wait();<br />如果你有jprofile或者其他的观察线程的工具,你可以看到有10个线程都在休眠状态.<br />  接着,我们向ThreadPool中加入任务,这些任务都实现了Runnable的run方法.(至于为什么把任务都做成Runnable,译者至今也有些疑问?预定俗成?TimerTask也是实现自Runnable,弄得初学者经常把真正运行的线程搞混).ThreadPool每assign一个任务,就会发出一条消息,通知它的等待锁定池中的线程.各个线程以抢占的方式获得对象锁,然后很顺利的获得一条任务.并把此任务从ThreadPool里面删除.没有抢到的继续等待.<br />Runnable r = (Runnable)assignments.iterator().next();<br />   assignments.remove(r);<br />WorkerThread从ThreadPool那里获得了任务，继续向下执行。<br />target = owner.getAssignment();<br />   if (target!=null) {<br />    target.run();      <br />    owner.done.workerEnd();<br />   }<br />记住，这里调用的是target.run();而不是调用的线程的start()方法。也就是说在这里表现出的WorkerThread和task之间的关系仅仅是简单的方法调用的关系，并没有额外产生新线程。（这就是我上面纳闷为什么大家都实现Runnable来做task的原因）<br /> 大家可能注意到，WorkerThread并没有对异常作处理。而我们知道发生在线程上的异常会导致线程死亡。解决的办法有2中，一种是通过threadpool的管理来重新激起一个线程，一种是把异常在线程之内消灭。在项目中，我采用的是第二中，因此这个片断改称这样：<br />if (target!=null) {<br />  try{<br />    target.run();      <br />   }<br />  catch(Throwable t){<br /> .......<br />   }<br />    owner.done.workerEnd();<br />}<br />在WorkerThread完成一个task以后,继续循环作同样的流程.<br />在这个ThreadPool的实现里面,Jeff Heaton用了一个Done类来观察WorkerThread的执行情况.和ThreadPoool的等待锁定池不同,Done的等待锁定池里面放的是初始化ThreadPool的线程(可能是你的主线程),我们叫他母线程.<br />  在给出的测试例子中.母线程在调用complete()方法后进入休眠(在监视中等待),一开始是waitBegin()让他休眠,在assign加入task以后,waitDone()方法让他休眠.在WorkerThread完成一个task以后,通知waitDone()起来重新检查activeThreads的数值.若不为0,继续睡觉.若为0,那么母线程走完,死亡(这个时候该做的task已经做完了).母线程走完,ThreadPool还存在吗?答案是存在,因为WorkerThread还没有消亡,他们在等待下一批任务,他们有ThreadPool的引用,保证ThreadPool依然存在.大家或许已经明白Done这个类的作用了.<br />  细心的读者或许会发现,发生在Done实例上的notify()并不是像ThreadPool上的notify()那样每次都能完成一项工作.比如除了第一个被assign的task,其他的task在assign进去的时候,发出的notify()对于waitDone()来说是句"狼来了".<br /> 最后在ThreadPool需要被清理得时候,使每一个WorkerThread中断(这个时候或许所有的WorkerThread都在休眠)并销毁.记住这里也是一个异步的过程.等到每一个WorkerThread都已经销毁,finalize()的方法体走完.ThreadPool被销毁.<br /> for (int i=0;i&lt;threads.length;i++) {<br />   threads[i].interrupt();<br />   done.workerBegin();<br />   threads[i].destroy();<br />  }<br />  done.waitDone();<br />为什么有句done.workerBegin();?不明白.<br />参考文章:<br /><a href="http://www.zdnet.com.cn/developer/common/printfriend/printfriendly.htm?AT=39276905-3800066897t-20000560c">http://www.zdnet.com.cn/developer/common/printfriend/printfriendly.htm?AT=39276905-3800066897t-20000560c</a><img src ="http://www.blogjava.net/huabingl/aggbug/58451.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/huabingl/" target="_blank">binge</a> 2006-07-16 20:07 <a href="http://www.blogjava.net/huabingl/archive/2006/07/16/58451.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>java.util.Date和java.sql.Date</title><link>http://www.blogjava.net/huabingl/archive/2006/07/06/56977.html</link><dc:creator>binge</dc:creator><author>binge</author><pubDate>Thu, 06 Jul 2006 08:51:00 GMT</pubDate><guid>http://www.blogjava.net/huabingl/archive/2006/07/06/56977.html</guid><wfw:comment>http://www.blogjava.net/huabingl/comments/56977.html</wfw:comment><comments>http://www.blogjava.net/huabingl/archive/2006/07/06/56977.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/huabingl/comments/commentRss/56977.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/huabingl/services/trackbacks/56977.html</trackback:ping><description><![CDATA[java.sql.Date,java.sql.Time和java.sql.Timestamp三个都是java.util.Date的子类（包装类）。<br />但是为什么java.sql.Date类型的值插入到数据库中Date字段中会发生数据截取呢？<br />java.sql.Date是为了配合SQL DATE而设置的数据类型。“规范化”的java.sql.Date只包含年月日信息，时分秒毫秒都会清零。格式类似：YYYY-MM-DD<br />当我们调用ResultSet的getDate()方法来获得返回值时，java程序会参照"规范"的java.sql.Date来格式化数据库中的数值。因此，如果<br />数据库中存在的非规范化部分的信息将会被劫取。在sun提供的ResultSet.java中这样对getDate进行注释的：<br />Retrieves the value of the designated column in the current row of this &lt;code&gt;ResultSet&lt;/code&gt; object as a “java.sql.Date” object in the Java programming language.<br />同理。如果我们把一个java.sql.Date值通过PrepareStatement的setDate方法存入数据库时，java程序会对传入的java.sql.Date规范化<br />，非规范化的部分将会被劫取。<br /> 然而，我们java.sql.Date一般由java.util.Date转换过来，如：java.sql.Date sqlDate=new java.sql.Date(new java.util.Date().getTime()).<br /> 显然，这样转换过来的java.sql.Date往往不是一个规范的java.sql.Date.<br /> 在<a href="http://www.thunderguy.com/semicolon/2003/08/14/java-sql-date-is-not-a-real-date/">http://www.thunderguy.com/semicolon/2003/08/14/java-sql-date-is-not-a-real-date/</a> 文章中提到，要保存java.util.Date的精确值，<br /> 我们需要利用java.sql.Timestamp.<br /> 感谢这篇文章的铺垫：<a href="http://community.csdn.net/Expert/topic/4354/4354971.xml?temp=.5256616">http://community.csdn.net/Expert/topic/4354/4354971.xml?temp=.5256616</a><img src ="http://www.blogjava.net/huabingl/aggbug/56977.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/huabingl/" target="_blank">binge</a> 2006-07-06 16:51 <a href="http://www.blogjava.net/huabingl/archive/2006/07/06/56977.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>关于异常Exception</title><link>http://www.blogjava.net/huabingl/archive/2006/06/29/55710.html</link><dc:creator>binge</dc:creator><author>binge</author><pubDate>Thu, 29 Jun 2006 03:40:00 GMT</pubDate><guid>http://www.blogjava.net/huabingl/archive/2006/06/29/55710.html</guid><wfw:comment>http://www.blogjava.net/huabingl/comments/55710.html</wfw:comment><comments>http://www.blogjava.net/huabingl/archive/2006/06/29/55710.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/huabingl/comments/commentRss/55710.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/huabingl/services/trackbacks/55710.html</trackback:ping><description><![CDATA[
		<p>1。什么是异常<br />   异常是一种状态，是程序出现了符合该异常条件的一种状态。因此，他也可以说成是一种条件。<br />2。为什么要捕获异常<br />  捕获异常是为了对程序中出现的某种状况进行处理。如果有异常而没有捕获，异常将会向上一层传播，最终导致线程在此中止。<br />3。什么是check异常和unchecked异常<br />  uncheck异常一般是RuntimeException.出现这类异常，编译器不会强制要用户去捕获（当然你可以捕获）。   编译器会强制要求用户对checked异常进行捕获并作出一定的处理。<br />4。为什么不推荐捕获顶层异常(Exception)<br />  程序中会发生各种各样的异常。除非你的程序是个终端（一个业务的终点），否则不推荐捕获顶层异常。<br /> 在程序的中间环节捕获所有异常毫无意义，并有可能导致流程上的隐患。比如，出现某种异常后，期望线程就此结束，不去做下面的工作，但是如果在中间环节对顶层异常进行了非法处理，程序有可能会运行下去，将导致不可控的错误。<br />5。为什么要自定义异常<br /> 自定义异常是为了设置异常链的起点。一般情况下，我们都是允许每个程序员看到所有的异常信息，这个时候大多数都是把下一层的异常直接重掷到上一层。然而在多层次的结构中，我们有时候需要隐藏底层异常（这种异常的信息很多，很枯燥），而给消费者提供一个更为直观的异常，这个时候我们需要自定义异常。有的异常类jdk已经给我们提供，比如常用的IllegalArgumentException。如果你想在此再作包装，你可以创建自己的异常类。如此，消费者将以此异常作为异常链的起点。<br />6。为什么要重掷异常<br /> 重掷异常是处理异常的一种方式。在捕获了某种异常后，用户可能不希望在这一层做出裁决，或者即使做出了一定的处理，但仍然需要向上一层报告，因此需要重掷异常。<br />7。异常机制。<br />   一旦某个点发生异常，这个点下面和catch语句之间的代码将不会被执行。因此，异常是一种中止流程的很有效的机制。<br />   关于异常，在effective java中提到“异常转译”和“异常连接”的概念。本人倾向于用“异常转译”，前提是要配置log4j,并作详细的日志纪录。</p>
<img src ="http://www.blogjava.net/huabingl/aggbug/55710.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/huabingl/" target="_blank">binge</a> 2006-06-29 11:40 <a href="http://www.blogjava.net/huabingl/archive/2006/06/29/55710.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转]一篇不错的讲解Java异常的文章</title><link>http://www.blogjava.net/huabingl/archive/2006/05/31/49343.html</link><dc:creator>binge</dc:creator><author>binge</author><pubDate>Wed, 31 May 2006 14:20:00 GMT</pubDate><guid>http://www.blogjava.net/huabingl/archive/2006/05/31/49343.html</guid><wfw:comment>http://www.blogjava.net/huabingl/comments/49343.html</wfw:comment><comments>http://www.blogjava.net/huabingl/archive/2006/05/31/49343.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/huabingl/comments/commentRss/49343.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/huabingl/services/trackbacks/49343.html</trackback:ping><description><![CDATA[
		<div>六种异常处理的陋习 <br /><br />　　你觉得自己是一个Java专家吗？是否肯定自己已经全面掌握了Java的异常处理机制？在下面这段代码中，你能够迅速找出异常处理的六个问题吗？ <br /><br />　　1 OutputStreamWriter out = ... <br /><br />　　2 java.sql.Connection conn = ... <br /><br />　　3 try { // ⑸ <br /><br />　　4 　Statement stat = conn.createStatement(); <br /><br />　　5 　ResultSet rs = stat.executeQuery( <br /><br />　　6 　　"select uid, name from user"); <br /><br />　　7 　while (rs.next()) <br /><br />　　8 　{ <br /><br />　　9 　　out.println("ID：" + rs.getString("uid") // ⑹ <br /><br />　　10 　　　"，姓名：" + rs.getString("name")); <br /><br />　　11 　} <br /><br />　　12 　conn.close(); // ⑶ <br /><br />　　13 　out.close(); <br /><br />　　14 } <br /><br />　　15 catch(Exception ex) // ⑵ <br /><br />　　16 { <br /><br />　　17 　ex.printStackTrace(); //⑴，⑷ <br /><br />　　18 } <br /><br />　　作为一个Java程序员，你至少应该能够找出两个问题。但是，如果你不能找出全部六个问题，请继续阅读本文。 <br /><br />　　本文讨论的不是Java异常处理的一般性原则，因为这些原则已经被大多数人熟知。我们要做的是分析各种可称为“反例”（anti-pattern）的违背优秀编码规范的常见坏习惯，帮助读者熟悉这些典型的反面例子，从而能够在实际工作中敏锐地察觉和避免这些问题。 <br /><br />　　反例之一：丢弃异常 <br /><br />　　代码：15行-18行。 <br /><br />　　这段代码捕获了异常却不作任何处理，可以算得上Java编程中的杀手。从问题出现的频繁程度和祸害程度来看，它也许可以和C/C++程序的一个恶名远播的问题相提并论??不检查缓冲区是否已满。如果你看到了这种丢弃（而不是抛出）异常的情况，可以百分之九十九地肯定代码存在问题（在极少数情况下，这段代码有存在的理由，但最好加上完整的注释，以免引起别人误解）。 <br /><br />　　这段代码的错误在于，异常（几乎）总是意味着某些事情不对劲了，或者说至少发生了某些不寻常的事情，我们不应该对程序发出的求救信号保持沉默和无动于衷。调用一下printStackTrace算不上“处理异常”。不错，调用printStackTrace对调试程序有帮助，但程序调试阶段结束之后，printStackTrace就不应再在异常处理模块中担负主要责任了。 <br /><br />　　丢弃异常的情形非常普遍。打开JDK的ThreadDeath类的文档，可以看到下面这段说明：“特别地，虽然出现ThreadDeath是一种‘正常的情形’，但ThreadDeath类是Error而不是Exception的子类，因为许多应用会捕获所有的Exception然后丢弃它不再理睬。”这段话的意思是，虽然ThreadDeath代表的是一种普通的问题，但鉴于许多应用会试图捕获所有异常然后不予以适当的处理，所以JDK把ThreadDeath定义成了Error的子类，因为Error类代表的是一般的应用不应该去捕获的严重问题。可见，丢弃异常这一坏习惯是如此常见，它甚至已经影响到了Java本身的设计。 <br /><br />　　那么，应该怎样改正呢？主要有四个选择： <br /><br />　　1、处理异常。针对该异常采取一些行动，例如修正问题、提醒某个人或进行其他一些处理，要根据具体的情形确定应该采取的动作。再次说明，调用printStackTrace算不上已经“处理好了异常”。 <br /><br />　　2、重新抛出异常。处理异常的代码在分析异常之后，认为自己不能处理它，重新抛出异常也不失为一种选择。 <br /><br />　　3、把该异常转换成另一种异常。大多数情况下，这是指把一个低级的异常转换成应用级的异常（其含义更容易被用户了解的异常）。 <br /><br />　　4、不要捕获异常。 <br /><br />　　结论一：既然捕获了异常，就要对它进行适当的处理。不要捕获异常之后又把它丢弃，不予理睬。 <br /><br />　　反例之二：不指定具体的异常 <br /><br />　　代码：15行。 <br /><br />　　许多时候人们会被这样一种“美妙的”想法吸引：用一个catch语句捕获所有的异常。最常见的情形就是使用catch(Exception ex)语句。但实际上，在绝大多数情况下，这种做法不值得提倡。为什么呢？ <br /><br />　　要理解其原因，我们必须回顾一下catch语句的用途。catch语句表示我们预期会出现某种异常，而且<a href="http://www.it.com.cn/f/hotweb/056/8/126579.htm"><u><font color="#0000ff">希望</font></u></a>能够处理该异常。异常类的作用就是告诉Java编译器我们想要处理的是哪一种异常。由于绝大多数异常都直接或间接从java.lang.Exception派生，catch(Exception ex)就相当于说我们想要处理几乎所有的异常。 <br /><br />　　再来看看前面的代码例子。我们真正想要捕获的异常是什么呢？最明显的一个是SQLException，这是JDBC操作中常见的异常。另一个可能的异常是IOException，因为它要操作OutputStreamWriter。显然，在同一个catch块中处理这两种截然不同的异常是不合适的。如果用两个catch块分别捕获SQLException和IOException就要好多了。这就是说，catch语句应当尽量指定具体的异常类型，而不应该指定涵盖范围太广的Exception类。 <br /><br />　　另一方面，除了这两个特定的异常，还有其他许多异常也可能出现。例如，如果由于某种原因，executeQuery返回了null，该怎么办？答案是让它们继续抛出，即不必捕获也不必处理。实际上，我们不能也不应该去捕获可能出现的所有异常，程序的其他地方还有捕获异常的机会??直至最后由JVM处理。 <br /><br />　　结论二：在catch语句中尽可能指定具体的异常类型，必要时使用多个catch。不要试图处理所有可能出现的异常。 <br /><br />　　反例之三：占用资源不释放 <br /><br />　　代码：3行-14行。 <br /><br />　　异常改变了程序正常的执行流程。这个道理虽然简单，却常常被人们忽视。如果程序用到了文件、Socket、JDBC连接之类的资源，即使遇到了异常，也要正确释放占用的资源。为此，Java提供了一个简化这类操作的关键词finally。 <br /><br />　　finally是样好东西：不管是否出现了异常，Finally保证在try/catch/finally块结束之前，执行清理任务的代码总是有机会执行。遗憾的是有些人却不习惯使用finally。 <br /><br />　　当然，编写finally块应当多加小心，特别是要注意在finally块之内抛出的异常??这是执行清理任务的最后机会，尽量不要再有难以处理的错误。 <br /><br />　　结论三：保证所有资源都被正确释放。充分运用finally关键词。 <br /><br />　　反例之四：不说明异常的详细信息 <br /><br />　　代码：3行-18行。 <br /><br />　　仔细观察这段代码：如果循环内部出现了异常，会发生什么事情？我们可以得到足够的信息判断循环内部出错的原因吗？不能。我们只能知道当前正在处理的类发生了某种错误，但却不能获得任何信息判断导致当前错误的原因。 <br /><br />　　printStackTrace的堆栈跟踪功能显示出程序运行到当前类的执行流程，但只提供了一些最基本的信息，未能说明实际导致错误的原因，同时也不易解读。 <br /><br />　　因此，在出现异常时，最好能够提供一些文字信息，例如当前正在执行的类、方法和其他状态信息，包括以一种更适合阅读的方式整理和组织printStackTrace提供的信息。 <br /><br />　　结论四：在异常处理模块中提供适量的错误原因信息，组织错误信息使其易于理解和阅读。 <br /><br />　　反例之五：过于庞大的try块 <br /><br />　　代码：3行-14行。 <br /><br />　　经常可以看到有人把大量的代码放入单个try块，实际上这不是好习惯。这种现象之所以常见，原因就在于有些人图省事，不愿花时间分析一大块代码中哪几行代码会抛出异常、异常的具体类型是什么。把大量的语句装入单个巨大的try块就象是出门旅游时把所有日常用品塞入一个大箱子，虽然东西是带上了，但要找出来可不容易。 <br /><br />　　一些新手常常把大量的代码放入单个try块，然后再在catch语句中声明Exception，而不是分离各个可能出现异常的段落并分别捕获其异常。这种做法为分析程序抛出异常的原因带来了困难，因为一大段代码中有太多的地方可能抛出Exception。 <br />结论五：尽量减小try块的体积。 <br /><br />　　反例之六：输出数据不完整 <br /><br />　　代码：7行-11行。 <br /><br />　　不完整的数据是Java程序的隐形杀手。仔细观察这段代码，考虑一下如果循环的中间抛出了异常，会发生什么事情。循环的执行当然是要被打断的，其次，catch块会执行??就这些，再也没有其他动作了。已经输出的数据怎么办？使用这些数据的人或设备将收到一份不完整的（因而也是错误的）数据，却得不到任何有关这份数据是否完整的提示。对于有些系统来说，数据不完整可能比系统停止运行带来更大的损失。 <br /><br />　　较为理想的处置办法是向输出设备写一些信息，声明数据的不完整性；另一种可能有效的办法是，先缓冲要输出的数据，准备好全部数据之后再一次性输出。 <br /><br />　　结论六：全面考虑可能出现的异常以及这些异常对执行流程的影响。 <br /><br />　　改写后的代码 <br /><br />　　根据上面的讨论，下面给出改写后的代码。也许有人会说它稍微有点?嗦，但是它有了比较完备的异常处理机制。 <br /><br />　　OutputStreamWriter out = ... <br /><br />　　java.sql.Connection conn = ... <br /><br />　　try { <br /><br />　　Statement stat = conn.createStatement(); <br /><br />　　ResultSet rs = stat.executeQuery( <br /><br />　　"select uid, name from user"); <br /><br />　　while (rs.next()) <br /><br />　　{ <br /><br />　　out.println("ID：" + rs.getString("uid") + "，姓名: " + rs.getString("name")); <br /><br />　　} <br /><br />　　} <br /><br />　　catch(SQLException sqlex) <br /><br />　　{ <br /><br />　　out.println("警告：数据不完整"); <br /><br />　　throw new ApplicationException("读取数据时出现SQL错误", sqlex); <br /><br />　　} <br /><br />　　catch(IOException ioex) <br /><br />　　{ <br /><br />　　throw new ApplicationException("写入数据时出现IO错误", ioex); <br /><br />　　} <br /><br />　　finally <br /><br />　　{ <br /><br />　　if (conn != null) { <br /><br />　　try { <br /><br />　　　conn.close(); <br /><br />　　} <br /><br />　　catch(SQLException sqlex2) <br /><br />　　{ <br /><br />　　　System.err(this.getClass().getName() + ".mymethod - 不能关闭数据库连接: " + sqlex2.toString()); <br /><br />　　} <br /><br />　　} <br /><br />　　if (out != null) { <br /><br />　　try { <br /><br />　　　out.close(); <br /><br />　　} <br /><br />　　catch(IOException ioex2) <br /><br />　　{ <br /><br />　　System.err(this.getClass().getName() + ".mymethod - 不能关闭输出文件" + ioex2.toString()); <br /><br />　　} <br /><br />　　} <br /><br />　　} <br /><br /><br />　　本文的结论不是放之四海皆准的教条，有时常识和经验才是最好的老师。如果你对自己的做法没有百分之百的信心，务必加上详细、全面的注释。 <br /><br />　　另一方面，不要笑话这些错误，不妨问问你自己是否真地彻底摆脱了这些坏习惯。即使最有经验的程序员偶尔也会误入歧途，原因很简单，因为它们确确实实带来了“方便”。所有这些反例都可以看作Java编程世界的恶魔，它们美丽动人，无孔不入，时刻诱惑着你。也许有人会认为这些都属于鸡皮蒜毛的小事，不足挂齿，但请记住：勿以恶小而为之，勿以善小而不为。 </div>
		<div>来自：<a href="http://www.it.com.cn/f/edu/0512/31/218593_1.htm"><font color="#e68328">http://www.it.com.cn/f/edu/0512/31/218593_1.htm</font></a></div>
		<div>参考：<a href="http://forum.javaeye.com/viewtopic.php?t=2038&amp;postdays=0&amp;pos"><font color="#e68328">http://forum.javaeye.com/viewtopic.php?t=2038&amp;postdays=0&amp;pos</font></a></div>
<img src ="http://www.blogjava.net/huabingl/aggbug/49343.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/huabingl/" target="_blank">binge</a> 2006-05-31 22:20 <a href="http://www.blogjava.net/huabingl/archive/2006/05/31/49343.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>