??xml version="1.0" encoding="utf-8" standalone="yes"?>
public static void replaceBlank()
{
Pattern p = Pattern.compile(\\s*|\t|\r|\n);
String str="I am a, I am Hello ok, \n new line ffdsa!";
System.out.println("before:"+str);
Matcher m = p.matcher(str);
String after = m.replaceAll("");
System.out.println("after:"+after);
}
public static void main(String[] args) {
replaceBlank();
}
}
// UsbHook.cpp : Defines the entry point for the application.
//
#include "stdafx.h"
#include "Dbt.h"
void DeviceChangeEventOpt(WPARAM wParam, LPARAM
lParam)
{
switch(wParam)
{
case
DBT_CONFIGCHANGECANCELED:
MessageBox(NULL,"讑֤改变DBT_CONFIGCHANGECANCELED","提示",MB_OK);
break;
case
DBT_CONFIGCHANGED:
MessageBox(NULL,"讑֤改变DBT_CONFIGCHANGED","提示",MB_OK);
break;
//case
DBT_CUSTOMEVENT:
// MessageBox(NULL,"讑֤改变DBT_CUSTOMEVENT","提示",MB_OK);
// break;
case
DBT_DEVICEARRIVAL: // A device has been inserted and is now available.
MessageBox(NULL,"讑֤改变DBT_DEVICEARRIVAL","提示",MB_OK);
DEV_BROADCAST_HDR
*stHDR;
stHDR = (DEV_BROADCAST_HDR *)lParam;
//判断讑֤cd
switch(stHDR->dbch_devicetype)
{
case
DBT_DEVTYP_DEVNODE:
MessageBox(NULL,"讑֤cd
DBT_DEVTYP_DEVNODE","提示",MB_OK);
break;
case DBT_DEVTYP_NET:
MessageBox(NULL,"讑֤cd DBT_DEVTYP_NET","提示",MB_OK);
break;
case
DBT_DEVTYP_OEM:
MessageBox(NULL,"讑֤cd
DBT_DEVTYP_OEM","提示",MB_OK);
break;
case
DBT_DEVTYP_PORT:
MessageBox(NULL,"讑֤cd
DBT_DEVTYP_PORT","提示",MB_OK);
break;
case
DBT_DEVTYP_VOLUME:// Logical volume. This structure is a DEV_BROADCAST_VOLUME
structure
MessageBox(NULL,"讑֤cd
DBT_DEVTYP_VOLUME","提示",MB_OK);
break;
}
//
break;
case
DBT_DEVICEQUERYREMOVE:
MessageBox(NULL,"讑֤改变DBT_DEVICEQUERYREMOVE","提示",MB_OK);
break;
case
DBT_DEVICEQUERYREMOVEFAILED:
MessageBox(NULL,"讑֤改变DBT_DEVICEQUERYREMOVEFAILED","提示",MB_OK);
break;
case
DBT_DEVICEREMOVECOMPLETE:// A device has been removed.
MessageBox(NULL,"讑֤改变DBT_DEVICEREMOVECOMPLETE","提示",MB_OK);
break;
case
DBT_DEVICEREMOVEPENDING://
MessageBox(NULL,"讑֤改变DBT_DEVICEREMOVEPENDING","提示",MB_OK);
break;
case
DBT_DEVICETYPESPECIFIC://
MessageBox(NULL,"讑֤改变DBT_DEVICETYPESPECIFIC","提示",MB_OK);
break;
case
DBT_QUERYCHANGECONFIG:
MessageBox(NULL,"讑֤改变DBT_QUERYCHANGECONFIG","提示",MB_OK);
break;
case
DBT_USERDEFINED
://
MessageBox(NULL,"讑֤改变DBT_USERDEFINED","提示",MB_OK);
break;
}
}
HWND hwndMain;
LRESULT CALLBACK WndProc(
HWND hwnd, //
handle to window
UINT uMsg, // message identifier
WPARAM wParam, // first message parameter
LPARAM lParam // second
message parameter
)
{
switch(uMsg)
{
case
WM_CREATE:
break;
case
WM_DESTROY:
PostQuitMessage(0);
break;
case
WM_COMMAND:
break;
case
WM_DEVICECHANGE:
DeviceChangeEventOpt(wParam,lParam);
break;
}
return
DefWindowProc(hwnd,uMsg,wParam,lParam);
}
int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE
hPrevInstance,
LPSTR
lpCmdLine,
int nCmdShow)
{
// TODO: Place
code here.
// TODO: Place code here.
WNDCLASSEX wclass;
MSG
msg;
wclass.cbClsExtra = 0;
wclass.cbSize =
sizeof(WNDCLASSEX);
wclass.cbWndExtra = 0;
wclass.hbrBackground =
(HBRUSH)GetStockObject(LTGRAY_BRUSH);
wclass.hCursor =
NULL;
wclass.hIcon = NULL;
wclass.hIconSm = NULL;
wclass.hInstance =
hInstance;
wclass.lpfnWndProc =(WNDPROC)WndProc;
wclass.lpszClassName =
"CheckUSB";
wclass.lpszMenuName = NULL;
wclass.style =
CS_DBLCLKS;
if(!RegisterClassEx(&wclass))
{
MessageBox(NULL,"cd建失?,"cd建失?,MB_OK);
}
hwndMain
= CreateWindow("CheckUSB","USB讑֤",
WS_OVERLAPPED | WS_SYSMENU |
WS_MINIMIZEBOX | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, 320, 300,NULL, NULL,
hInstance,
NULL);
while(GetMessage(&msg,NULL,0,0))
{
TranslateMessage(&msg); //translate
the message into its char
equivelent
DispatchMessage(&msg);
}
return msg.wParam;
}
原帖来自http://search.csdn.net/Expert/topic/989/989392.xml?temp=.1137812
代码中有部分参数意思不是很明确Q在参考了msdn后做了一定的改动。用U盘测试ƈ没有什么问题。反正那几个参数标识的也不是U盘的参数?br />
用USB鼠标和键盘测试ƈ没有反映Q但是可以监视USB存储讑֤感觉已经辑ֈ要求了,有时间再改进一?/p>
最q网上流行通过AutoRun.inf文g使对Ҏ(gu)有的盘完全׃n或中木马的方法,׃AutoRun.inf文g在黑客技术中的应用还是很见的,相应的资料也不多Q有很多人对此觉得很秘Q本文试图ؓ(f)(zhn)解开q个qP使?zhn)能完全的了解q个q不复杂却极其有的技术?
一、理论基
l常使用光盘的朋友都知道Q有很多光盘攑օ光驱׃(x)自动q行Q它们是怎么做的呢?光盘一攑օ光驱׃(x)自动被执行,主要依靠两个文gQ一是光盘上的AutoRun.inf文gQ另一个是操作pȝ本n的系l文件之一的Cdvsd.vxd。Cdvsd.vxd?x)随时侦光׃是否有放入光盘的动作Q如果有的话Q便开始寻扑օ盘根目录下的AutoRun.inf文g。如果存在AutoRun.inf文g则执行它里面的预讄序?
AutoRun.inf不光能让光盘自动q行E序Q也能让盘自动q行E序Q方法很单,先打开C本,然后用鼠标右键点击该文gQ在弹出菜单中选择“重命?#8221;Q将其改名ؓ(f)AutoRun.infQ在AutoRun.inf中键入以下内容:(x)
|
保存该文Ӟ按F5h桌面Q再?#8220;我的?sh)?#8221;中的该盘W?在此为C?Q你?x)发现它的磁盘图标变了,双击q入C盘,q会(x)自动播放C盘下?.exe文gQ?
解释一下:(x)“[AutoRun]”行是必须的固定格式,“Icon”行对应的是图标文Ӟ“C:\C.ico”为图标文件\径和文g名,你在输入时可以将它改Z的图片文件所在\径和文g名。另外,“.ico”为图标文件的扩展名,如果你手头上没有q类文gQ可以用看图软gACDSee其他格式的软g转换为ico格式Q或者找C个后~名ؓ(f)BMP的文Ӟ它直接改名为ICO文g卛_?
“Open”行指定要自动q行的文件及(qing)其盘W和路径。要特别说明的是Q如果你要改变的盘跟目录下没有自动播放文gQ就应该?#8220;OPEN”行删掉,否则׃(x)因ؓ(f)找不到自动播放文件而打不开盘Q此时只能用鼠标右键单击盘符在弹单中?#8220;打开”才行?
请大家注意:(x)保存的文件名必须?#8220;AutoRun.inf”Q编制好的Autorun.inf文g和图标文件一定要攑֜盘根目录下。更q一步,如果你的某个盘内容暂时比较固定的话Q不妨用Flash做一个自动播放文Ӟ再编?#8220;Autorun”文gQ那你就有最酗最个性的盘了?
到这儿还没有完。大家知道,在一些光盘放入后Q我们在其图标上单击鼠标右键Q还?x)生一个具有特色的目录菜单Q如果能对着我们的硬盘点击鼠标右键也产生q样的效果,那将更加的有特色。其实,光盘能有q样的效果也仅仅是因为在AutoRun.inf文g中有如下两条语句Q?
|
所以,要让盘h特色的目录菜单,在AutoRun.inf文g中加入上q语句即可,CZ如下Q?
|
保存完毕Q按F5键刷斎ͼ然后用鼠标右键单ȝ盘图标,在弹单中?x)发?#8220;天若有情天亦?#8221;Q点dQ会(x)自动打开盘中的“ok.txt”文g。注意:(x)上面CZ假设“ok.txt”文g在硬盘根目录下,notepad为系l自带的C本程序。如果要执行的文件ؓ(f)直接可执行程序,则在“command\”后直接添加该执行E序文g名即可?
二、实?/strong>
下面׃D个例子:(x)如果你扫C台开着139׃n的机器,而对方只完全׃n了D盘,我们要让Ҏ(gu)的所有驱动器都共享。首先编辑一个注册表文gQ打开C本,键入以下内容Q?
|
以上我只讄到E盘,如果Ҏ(gu)有很多逻辑盘符的请自行讄。将以上部分另存为Share.reg文g备用。要特别注意REGEDIT4为大写且格书写Q其后要IZ一行,在最后一行记得要按一ơ回车键?
然后打开C本,~制一个AutoRun.inf文gQ键入以下内容:(x)
|
保存AutoRun.inf文g。将Share.reg和AutoRun.infq两个文仉复制到对方的D盘的根目录下Q这样对方只要双击D盘就?x)将Share.reg导入注册表,q样Ҏ(gu)?sh)脑重启后所有驱动器׃(x)都完全共享出来?
如果惌Ҏ(gu)中木马,只要在AutoRun.inf文g中,?#8220;Open=Share.Reg”Ҏ(gu)“Open=木马服务端文件名”Q然后把AutoRun.inf和配|好的木马服务端一起复制到Ҏ(gu)D盘的根目录下Q这样不需Ҏ(gu)q行木马服务端程序,而只需他双击D盘就?x)木马q行Q这样做的好处显而易见,那就是大大的增加了木马运行的d性!ȝ许多人现在都是非常警惕的Q不熟?zhn)的文件他们轻易的不?x)q行Q而这U方法就很难防范了?
要说明的是,l你下木马的Z?x)那么蠢的不l木马加以伪装,一般说来,他们?x)给木马服务端文件改个名字,或好听或和系l文件名很相像,然后l木马换个图标,使它看v来像TXT文g、ZIP文g或图片文件等Q,最后修Ҏ(gu)马的资源文g使其不被杀毒Y件识别(具体的方法可以看本刊以前的文章)Q当服务端用户信以ؓ(f)真时Q木马却(zhn)?zhn)侵入了系l。其实,换个角度理解׃难了——要是?zhn)l别Z木马我想你也?x)这样做的。以上手D再辅以如上内容的AutoRun.inf文g天衣无~了Q?
三、防范方?/strong>
׃n分类完全是由flags标志军_的,它的键值决定了׃n目录的类型。当flags=0x302Ӟ重新启动pȝQ目录共享标志消失,表面上看没有׃nQ实际上该目录正处于完全׃n状态。网上流行的׃n蠕虫Q就是利用了此特性。如果把"Flags"=dword:00000302Ҏ(gu)"Flags"=dword:00000402Q就可以看到盘被共享了Q明白了吗?U密在q里Q?
以上代码中的Parmlenc、Parm2enc属性项是加密的密码Q系l在加密旉用了8位密码分别与“35 9a 4b a6 53 a9 d4 6a”q行异或q算Q要x出密码再q行一ơ异或运,然后查ASCII表可得出目录密码。在|络软g中有一ƾY件就利用该属性进行网l密码破解的Q在局域网内从一台机器上可以看到另一台计机的共享密码?
利用TCP/IP协议设计的NethackerⅡY件可以穿qInternet|络Q找到共享的LQ然后进行相应操作。所以当(zhn)通过Modem上网Ӟ千万要小心,因ؓ(f)一不小心,(zhn)的L完全共享给Ҏ(gu)了?
解决办法是把
|
|
另外Q关闭硬盘AutoRun功能也是防范黑客入R的有效方法之一。具体方法是?#8220;开?#8221;菜单?#8220;q行”中输入RegeditQ打开注册表编辑器Q展开?
|
双击“NoDriveTypeAutoRun”Q在默认状态下Q即你没有禁止过AutoRun功能Q,在弹出窗口中可以看到“NoDriveTypeAutoRun”默认键gؓ(f)95,00,00,00。其中第一个?#8220;95”是十六进制|它是所有被止自动q行讑֤的和。将“95”转ؓ(f)二进制就?0010101Q其中每位代表一个设备,W(xu)indows中不同设备会(x)用如下数DC:(x)
|
在上面所列的表中gؓ(f)“0”表示讑֤q行Qgؓ(f)“1”表示该设备不q行Q默认情况下QW(xu)indows止80h?0h?h?1hq些讑֤自动q行Q这些数值篏加正好是十六q制?5hQ所以NoDriveTypeAutoRun”默认键gؓ(f)95,00,00,00Q?
׃面的分析不难看出Q在默认情况下,?x)自动运行的讑֤是DRIVE_NO_ROOT_DIR、DRIVE_FIXED、DRIVE_CDROM、DRIVE_RAMDISKq四个保留设备,所以要止盘自动q行AutoRun.inf文gQ就必须DRIVE_FIXED的D?Q这是因为DRIVE_FIXED代表固定的驱动器Q即盘。这样一来,原来?0010101Q在表中“?#8221;列中׃向上看)变成了二进制的10011101Q{为十六进制ؓ(f)9D。现在,?#8220;NoDriveTypeAutoRun”的键值改?D,00,00,00后关闭注册表~辑器,重启?sh)脑后就会(x)关闭硬盘的AutoRun功能?
如果你看明白了,那你肯定知道该怎样止光盘AutoRun功能了,对!是DRIVE_CDROM设ؓ(f)1Q这?#8220;NoDriveTypeAutoRun”键g的第一个值就变成?0110101Q也是十六q制的B5。将W一个值改为B5后关闭注册表~辑器,重启?sh)脑后就会(x)关闭CDROM的Autorun功能。如果仅想禁止Y件光盘的AutoRun功能Q但又保留对CD音频的自动播放能力Q这时只需?#8220;NoDriveTypeAutoRun”的键值改为:(x)BD,00,00,00卛_?
如果惌恢复盘或光qAutoRun功能Q进行反方向操作卛_?
事实上,大多数的盘根目录下q不需要AutoRun.inf文g来运行程序,因此我们完全可以硬盘的AutoRun功能关闭Q这样即使在盘根目录下有AutoRun.infq个文gQW(xu)indows也不?x)去q行其中指定的程序,从而可以达到防止黑客利用AutoRun.inf文g入R的目的?
除此以外Q我们还应让Windows能显C出隐藏的共享。大安知道Q在Windows 9X中设|共享时Q通过在共享名后加?#8220;$”q个W号Q可使共享隐藏。比如,我们l一个名为share的计机的C盘设|共享时Q只要将其共享名设ؓ(f)C$。这h们将看不到被׃n的C盘,只有通过输入该共享的切路径Q才能访问此׃n。不q我们只要用电(sh)脑中的msnp32.dll文gE做修改。就可以让Windows昄出隐藏的׃n?
׃在Windows下msnp32.dll?x)被调用Q不能直接修Ҏ(gu)文gQ所以第一步我们要复制msnp32.dll到C盘下q改名ؓ(f)msnp32Qmsnp32.dll在C:\Windows\system文g夹下。运行UltraEdit{十六进制文件编辑器打开msnp32Q找?#8220;24 56 E8 17”Q位于偏Ud址00003190?00031A0处)Q找到后?#8220;24”改ؓ(f)“00”Q然后保存,关闭UltraEdit。重启计机q入DOS模式Q在命o(h)提示W下输入copy c:\msnp32.dll c:\Windows\system\msnp32.dllQ重启进入WindowsQ现在双击sharep看见被隐藏的׃n了?
最后要提醒大家利用TCP/IP协议设计的NethackerⅡ等黑客软g可以I过Internet|络Q找到共享的LQ然后进行相应操作。所以当(zhn)通过Modem上网Ӟ千万要小心,因ؓ(f)一不小心,(zhn)的L完全共享给Ҏ(gu)了。防范这cM情发生的Ҏ(gu)无非是经常检查系l,l系l打上补丁,l常使用反黑杀毒YӞ上网时打开防火墙,注意异常现象Q留意AutoRun.inf文g的内容,关闭׃n或不要设|ؓ(f)完全׃nQ且加上复杂的共享密码?
声明Q本文的目的是大家能清楚地了解|上行的黑客手D,增强自己的防护意识,因此请大家不要用本文的方法去q违法的事情Q切讎ͼ(x)己所不欲Q勿施于人!
Java执行环境本n是一个^収ͼ执行于这个^C的程序是已编译完成的JavaE序(JavaE序~译完成之后Q会(x)?class文g存在)。如果将Java执行环境比喻为操作系l,如果讄Path变量是ؓ(f)了让操作pȝ扑ֈ指定的工L(fng)?以Windows来说是扑ֈ.exe文g)Q?/span>则设|Classpath的目的就是让Java执行环境扑ֈ指定的JavaE序(也就?class文g)?/span>
讄classpath的时候需要注意,路径中不要包含到包的名字部分Q因为包Q在windows操作pȝ下)对应到目录结构,例如?Package com.pwcrab 其实是有一个com\pwcrab的相对\径存在。如果该包在C:\java\MyLib 下,完整的\径是C:\java\MyLib\com\pwcrab Q但是设|CLASSPATHӞ务必不要包含包部分的路径?span style="color: #0000ff">q有一点请注意QCLASSPATH中的 “.”表示是在当前目录下先L?/span>
但是Q在使用JAR文gӞ有一些例?strong>Q?/strong>必须在类路径中将JAR文g的实际名U写的完整清楚,而不仅仅是他们的目录位置Q例?#8220;.;C:\Program Files\Java\jdk1.5.0_06\lib\tools.jar; C:\Program Files\Java\jdk1.5.0_06\lib\rt.jar”(jar文g是zip压羃格式Q其中包?class文g和jar中的Classpath讄)Q每一路径中间必须?作ؓ(f)分隔?br />
TipsQpackage中的*.java也要记得~译?好像我的主要问题是这个,折腾了一个晚上睡醒一觉解决了……
1 OutputStreamWriter out = ... 2 java.sql.Connection conn = ... 3 try { // ? 4 Statement stat = conn.createStatement(); 5 ResultSet rs = stat.executeQuery( 6 "select uid, name from user"); 7 while (rs.next()) 8 { 9 out.println("IDQ? + rs.getString("uid") // ? 10 "Q姓名:(x)" + rs.getString("name")); 11 } 12 conn.close(); // ? 13 out.close(); 14 } 15 catch(Exception ex) // ? 16 { 17 ex.printStackTrace(); //_(d)? 18 } |
作ؓ(f)一个JavaE序员,你至应该能够找Z个问题。但是,如果你不能找出全部六个问题,L(fng)l阅L文?
本文讨论的不是Java异常处理的一般性原则,因ؓ(f)q些原则已经被大多数人熟知。我们要做的是分析各U可UCؓ(f)“反例”Qanti-patternQ的q背优秀~码规范的常见坏?fn)惯Q帮助读者熟(zhn)这些典型的反面例子Q从而能够在实际工作中敏锐地察觉和避免这些问题?
反例之一Q丢弃异?
代码Q?5?18行?
q段代码捕获了异常却不作M处理Q可以算得上Java~程中的杀手。从问题出现的频J程度和害E度来看Q它也许可以和C/C++E序的一个恶名远播的问题相提q论??不检查缓冲区是否已满。如果你看到了这U丢弃(而不是抛出)异常的情况,可以癑ֈ之九(ji)十九(ji)地肯定代码存在问题(在极数情况下,q段代码有存在的理由Q但最好加上完整的注释Q以免引起别解)?
q段代码的错误在于,异常Q几乎)L意味着某些事情不对劲了Q或者说臛_发生了某些不d的事情,我们不应该对E序发出的求救信号保持沉默和无动于衷。调用一下printStackTrace不?#8220;处理异常”。不错,调用printStackTrace对调试程序有帮助Q但E序调试阶段l束之后QprintStackTrace׃应再在异常处理模块中担负主要责Q了?
丢弃异常的情形非常普遍。打开JDK的ThreadDeathcȝ文档Q可以看C面这D说明:(x)“特别圎ͼ虽然出现ThreadDeath是一U?#8216;正常的情?#8217;Q但ThreadDeathcLError而不是Exception的子c,因ؓ(f)许多应用?x)捕h有的Exception然后丢弃它不再理睬?#8221;q段话的意思是Q虽然ThreadDeath代表的是一U普通的问题Q但鉴于许多应用?x)试图捕h有异常然后不予以适当的处理,所以JDK把ThreadDeath定义成了Error的子c,因ؓ(f)ErrorcM表的是一般的应用不应该去捕获的严重问题。可见,丢弃异常q一坏习(fn)惯是如此常见Q它甚至已经影响CJava本n的设计?
那么Q应该怎样Ҏ(gu)呢?主要有四个选择Q?
1、处理异常。针对该异常采取一些行动,例如修正问题、提醒某个h或进行其他一些处理,要根据具体的情Ş定应该采取的动作。再ơ说明,调用printStackTrace不上已l?#8220;处理好了异常”?
2、重新抛出异常。处理异常的代码在分析异怹后,认ؓ(f)自己不能处理它,重新抛出异常也不׃ؓ(f)一U选择?
3、把该异常{换成另一U异常。大多数情况下,q是指把一个低U的异常转换成应用的异常(其含义更Ҏ(gu)被用户了解的异常Q?
4、不要捕获异常?
l论一Q既然捕获了异常Q就要对它进行适当的处理。不要捕获异怹后又把它丢弃Q不予理睬?
反例之二Q不指定具体的异?
代码Q?5行?
许多时候h们会(x)被这样一U?#8220;妙?#8221;x吸引Q用一个catch语句捕获所有的异常。最常见的情形就是用catch(Exception ex)语句。但实际上,在绝大多数情况下Q这U做法不值得提倡。ؓ(f)什么呢Q?
要理解其原因Q我们必d一下catch语句的用途。catch语句表示我们预期?x)出现某U异常,而且希望能够处理该异常。异常类的作用就是告诉Java~译器我们想要处理的是哪一U异常。由于绝大多数异帔R直接或间接从java.lang.ExceptionzQcatch(Exception ex)q当于说我们想要处理几乎所有的异常?
再来看看前面的代码例子。我们真正想要捕L(fng)异常是什么呢Q最明显的一个是SQLExceptionQ这是JDBC操作中常见的异常。另一个可能的异常是IOExceptionQ因为它要操作OutputStreamWriter。显Ӟ在同一个catch块中处理q两U截然不同的异常是不合适的。如果用两个catch块分别捕获SQLException和IOExceptionp好多了。这是_(d)catch语句应当量指定具体的异常类型,而不应该指定늛范围太广的ExceptioncR?
另一斚wQ除了这两个特定的异常,q有其他许多异常也可能出现。例如,如果׃某种原因QexecuteQueryq回了nullQ该怎么办?{案是让它们l箋抛出Q即不必捕获也不必处理。实际上Q我们不能也不应该去捕获可能出现的所有异常,E序的其他地方还有捕获异常的Z(x)??直至最后由JVM处理?
l论二:(x)在catch语句中尽可能指定具体的异常类型,必要时用多个catch。不要试囑֤理所有可能出现的异常?
反例之三Q占用资源不释放
代码Q??14行?
异常改变了程序正常的执行程。这个道理虽然简单,却常常被Z忽视。如果程序用C文g、Socket、JDBCq接之类的资源,即遇到了异常,也要正确释放占用的资源。ؓ(f)此,Java提供了一个简化这cL作的关键词finally?
finally是样好东西:(x)不管是否出现了异常,Finally保证在try/catch/finally块结束之前,执行清理d的代码L有机?x)执行。遗憄是有些h却不?fn)惯使用finally?
当然Q编写finally块应当多加小心,特别是要注意在finally块之内抛出的异常??q是执行清理d的最后机?x),量不要再有难以处理的错误?
l论三:(x)保证所有资源都被正释放。充分运用finally关键词?/font>
反例之四Q不说明异常的详l信?
代码Q??18行?
仔细观察q段代码Q如果@环内部出C异常Q会(x)发生什么事情?我们可以得到_的信息判断@环内部出错的原因吗?不能。我们只能知道当前正在处理的cd生了某种错误Q但却不能获得Q何信息判断导致当前错误的原因?
printStackTrace的堆栈跟t功能显C出E序q行到当前类的执行流E,但只提供了一些最基本的信息,未能说明实际D错误的原因,同时也不易解诅R?
因此Q在出现异常Ӟ最好能够提供一些文字信息,例如当前正在执行的类、方法和其他状态信息,包括以一U更适合阅读的方式整理和l织printStackTrace提供的信息?
l论四:(x)在异常处理模块中提供适量的错误原因信息,l织错误信息使其易于理解和阅诅R?
反例之五Q过于庞大的try?
代码Q??14行?
l常可以看到有h把大量的代码攑օ单个try块,实际上这不是好习(fn)惯。这U现象之所以常见,原因在于有些h囄事,不愿花时间分析一大块代码中哪几行代码?x)抛出异常、异常的具体cd是什么。把大量的语句装入单个巨大的try块就象是出门旅游时把所有日常用品塞入一个大子Q虽然东西是带上了,但要扑և来可不容易?
一些新手常常把大量的代码放入单个try块,然后再在catch语句中声明ExceptionQ而不是分d个可能出现异常的D落q分别捕获其异常。这U做法ؓ(f)分析E序抛出异常的原因带来了困难Q因Z大段代码中有太多的地方可能抛出Exception?
l论五:(x)量减小try块的体积?
反例之六Q输出数据不完整
代码Q??11行?
不完整的数据是JavaE序的隐形杀手。仔l观察这D代码,考虑一下如果@环的中间抛出了异常,?x)发生什么事情。@环的执行当然是要被打断的Q其ơ,catch块会(x)执行??p些,再也没有其他动作了。已l输出的数据怎么办?使用q些数据的h或设备将收到一份不完整的(因而也是错误的Q数据,却得不到M有关q䆾数据是否完整的提C。对于有些系l来_(d)数据不完整可能比pȝ停止q行带来更大的损失?
较ؓ(f)理想的处|办法是向输备写一些信息,声明数据的不完整性;另一U可能有效的办法是,先缓冲要输出的数据,准备好全部数据之后再一ơ性输出?
l论六:(x)全面考虑可能出现的异总?qing)这些异常对执行程的媄响?
改写后的代码
Ҏ(gu)上面的讨论,下面l出改写后的代码。也许有Z(x)说它E微有点?嗦,但是它有了比较完备的异常处理机制?
OutputStreamWriter out = ... java.sql.Connection conn = ... try { Statement stat = conn.createStatement(); ResultSet rs = stat.executeQuery( "select uid, name from user"); while (rs.next()) { out.println("IDQ? + rs.getString("uid") + "Q姓? " + rs.getString("name")); } } catch(SQLException sqlex) { out.println("警告Q数据不完整"); throw new ApplicationException("d数据时出现SQL错误", sqlex); } catch(IOException ioex) { throw new ApplicationException("写入数据时出现IO错误", ioex); } finally { if (conn != null) { try { conn.close(); } catch(SQLException sqlex2) { System.err(this.getClass().getName() + ".mymethod - 不能关闭数据库连? " + sqlex2.toString()); } } if (out != null) { try { out.close(); } catch(IOException ioex2) { System.err(this.getClass().getName() + ".mymethod - 不能关闭输出文g" + ioex2.toString()); } } } |
aaa
bbb
ccc
ddd