




版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡介
1、【java編程】java中異步socket類的實(shí)現(xiàn)和源代碼- - java中異步socket類的實(shí)現(xiàn)和源代碼作者: HYPERLINK dozb我們知道,java中socket類一般操作都是同步進(jìn)行,常常在read的時(shí)候socket就會阻塞直到有數(shù)據(jù)可讀或socket連接斷開的時(shí)候才返回,雖然可以設(shè)置超時(shí)返回,但是這樣比較低效,需要做一個(gè)循環(huán)來不停掃描數(shù)據(jù)是否可讀??磥恚谕粋€(gè)線程中,要是想實(shí)現(xiàn)異步讀寫不太容易。下面介紹的這個(gè)類實(shí)現(xiàn)了偽異步socket通訊?;舅枷刖褪窃诂F(xiàn)有socket類的基礎(chǔ)上進(jìn)行封裝,當(dāng)socket連接建立成功后,立即創(chuàng)建一個(gè)socket數(shù)據(jù)接收線程,專門負(fù)責(zé)阻塞式的s
2、ocket讀取(read),而當(dāng)前線程負(fù)責(zé)數(shù)據(jù)的發(fā)送(send)。另外定義了一個(gè)接口,包括了socket的各種事件的回調(diào)。我們要實(shí)現(xiàn)這個(gè)接口,在接口實(shí)現(xiàn)類中創(chuàng)建異步socket對象,并且傳遞接口類到異步socket對象中,目的是有socket事件的時(shí)候回調(diào)我們的方法。下面是接口:SocketExHandler.java package ;import .*; /* * Title: * Description: * Copyright: Copyright (c) 2001 * Company: * author dozb * version 1.0 */* * 異步Socket Client
3、 Interface * 使用方法: * 1.定義類 MySocketClientEx 實(shí)現(xiàn)SocketExHandler接口,實(shí)現(xiàn) OnReceive OnClose OnConnect 事件 * 2.在類中實(shí)現(xiàn)start方法 MySocketEx = new SocketEx(this,ip,port) * 3.在類中實(shí)現(xiàn)stop方法 delete MySocketEx * 4.當(dāng)有數(shù)據(jù)到達(dá)時(shí)會觸發(fā)OnReceive事件 * 5.當(dāng)對方SOCKET關(guān)閉時(shí)會觸發(fā)OnClose事件 * 6.當(dāng)SOCKET建立時(shí)會觸發(fā)OnConnect事件 */* * 異步Socket Server Inter
4、face * 使用方法: * 1.定義類 MySocketServerEx 實(shí)現(xiàn)SocketExHandler接口,實(shí)現(xiàn) OnReceive OnListen OnClose OnAccept 事件 * 2.在類中實(shí)現(xiàn)start方法 MySocketEx = new ServerSocketEx(this,ip,port) * 3.在類中實(shí)現(xiàn)stop方法 delete MySocketEx * 4.當(dāng)開始監(jiān)聽時(shí)會觸發(fā)OnListen事件 * 5.當(dāng)SOCKET關(guān)閉時(shí)會觸發(fā)OnClose事件 * 6.當(dāng)有客戶端SOCKET要建立連接時(shí)會觸發(fā)OnAccept事件 */public interfac
5、e SocketExHandler/當(dāng)客戶端sock數(shù)據(jù)到達(dá)時(shí)觸發(fā)public void OnReceive(Object socket,byte buf,int nLen);/當(dāng)客戶端sock連接建立成功時(shí)觸發(fā)public void OnConnect(Object socket);/當(dāng)服務(wù)端sock監(jiān)聽開始時(shí)觸發(fā)public void OnListen(Object socket);/當(dāng)服務(wù)端sock接受一個(gè)新的sock連接時(shí)觸發(fā)public void OnAccept(Object socket,SocketEx ClientSocket) ;/當(dāng)sock關(guān)閉時(shí)觸發(fā)public void
6、 OnClose(Object socket); 下面是異步客戶端socket類: SocketEx.java package ;import java.io.*;import .*;import java.util.*;import .SocketExHandler;/* * Title: * Description: * Copyright: Copyright (c) 2001 * Company: * author dozb * version 1.0 */public class SocketEx implements Runnablepublic static final bool
7、ean isdebug = true;/調(diào)試/* *構(gòu)造函數(shù). */public SocketEx(SocketExHandler seh,Socket ClientSocket)this.seh = seh;thisSocket = ClientSocket;InitNotify();public SocketEx(SocketExHandler seh,String host,int port) throws IOException this.seh = seh;thisSocket = new Socket(host,port);InitNotify();public SocketEx(
8、SocketExHandler seh, InetAddress address, int port ) throws IOException this.seh = seh;thisSocket = new Socket(address, port);InitNotify();public SocketEx(SocketExHandler seh, String host, int port, InetAddress localAddr, int localPort ) throws IOException this.seh = seh;thisSocket = new Socket(host
9、,port,localAddr,localPort );InitNotify();public SocketEx(SocketExHandler seh, InetAddress address, int port, InetAddress localAddr, int localPort ) throws IOException this.seh = seh;thisSocket = new Socket(address, port, localAddr,localPort );InitNotify();/* * 實(shí)現(xiàn)Socket的可見方法. */public synchronized vo
10、id close() throws IOExceptionIsRunning = false;thisSocket.close();public InetAddress getInetAddress() return thisSocket.getInetAddress();public InputStream getInputStream() throws IOExceptionreturn thisSocket.getInputStream(); public InetAddress getLocalAddress() return thisSocket.getLocalAddress()
11、; public int getLocalPort() return thisSocket.getLocalPort() ; public OutputStream getOutputStream() throws IOExceptionreturn thisSocket.getOutputStream(); public int getPort() return thisSocket.getPort() ; public int getSoLinger() throws SocketExceptionreturn thisSocket.getSoLinger(); public synchr
12、onized int getSoTimeout() throws SocketException return thisSocket.getSoTimeout(); public boolean getTcpNoDelay() throws SocketException return thisSocket.getTcpNoDelay(); public void setSoLinger( boolean on, int val ) throws SocketException thisSocket.setSoLinger(on,val); public synchronized void s
13、etSoTimeout( int timeout ) throws SocketException thisSocket.setSoTimeout( timeout ) ; public void setTcpNoDelay( boolean on ) throws SocketException thisSocket.setTcpNoDelay(on); public String toString() return thisSocket.toString() ; /* * 獲取Socket */public Socket GetSocket()return thisSocket;/* *
14、初始化異步Socket */private void ShowMsg(String Msg)if(isdebug)System.out.println(Msg);private void InitNotify()if(NotifyThread != null) return ;trybiStream = new BufferedInputStream(getInputStream();thisSocket.setSoTimeout(0); catch(IOException e)ShowMsg(InitNotify() IOException.);IsRunning = true;Notify
15、Thread = new Thread(this,SocketEx_NoitfyThread);NotifyThread.setDaemon(true);NotifyThread.start();if(seh !=null)seh.OnConnect(this);/* * 關(guān)閉Socket */private void Close()tryclose();catch(Exception eclose)ShowMsg(Close() Exception.);protected void finalize() throws ThrowableClose();super.finalize();/*
16、* Thread 運(yùn)行 */public void run()while(IsRunning)tryif(getInputStream().read(buf,0,1) = 0)/試讀一個(gè)字節(jié)DoClose();return ;if(!DoReceive(getInputStream().available()return ;catch(Exception e)ShowMsg(run() Exception.);DoClose();return ;tryThread.sleep(0); /catch(InterruptedException e)ShowMsg(run() Interrupted
17、Exception.);DoClose();return ;/* * 當(dāng)有數(shù)據(jù)到達(dá)時(shí)的回調(diào)方法. */private boolean DoReceive(int nCanReadCount)tryint len = 0,nCurrReadCount=0,nStart=1;dofor(int i=nStart;i(BUFLEN-2)nCurrReadCount = BUFLEN-2;elsenCurrReadCount = nCanReadCount;len = biStream.read(buf,nStart,nCurrReadCount);if(len = 0)DoClose();retur
18、n false;nCanReadCount -= len;buflen+nStart = 0;if(seh !=null)seh.OnReceive(this,buf,len+nStart);nStart = 0;while(nCanReadCount 0); catch(Exception excpt)ShowMsg(DoReceive() Exception.);DoClose();return false; return true;/* * 當(dāng)Socket建立連接時(shí)的回調(diào)方法. */private void DoConnect()if(seh !=null)seh.OnConnect(t
19、his);/* * 當(dāng)Socket關(guān)閉時(shí)的回調(diào)方法. */private void DoClose()try if(IsRunning) Close(); if(seh !=null) seh.OnClose(this); IsRunning = false; catch(Exception e)ShowMsg(DoClose() Exception.);/* * 以下實(shí)現(xiàn)不要改動! */private Thread NotifyThread=null;private boolean IsRunning = false;private Socket thisSocket = null;priv
20、ate static final int BUFLEN = 4097;privatebyte buf = new byteBUFLEN;privateBufferedInputStream biStream = null;privateSocketExHandler seh=null; 下面是異步socketserver類: ServerSocketEx .java package ;import java.io.*;import .*; import java.util.*; /* * Title: * Description: * Copyright: Copyright (c) 2001
21、 * Company: * author dozb * version 1.0 */public class ServerSocketEx extends ServerSocket implements Runnable/* * 以下實(shí)現(xiàn)不要改動! */public ServerSocketEx(SocketExHandler seh, int port ) throws IOException super(port);this.seh = seh;Listen();public ServerSocketEx(SocketExHandler seh, int port, int backlog
22、 ) throws IOException super(port,backlog);this.seh = seh;Listen();public ServerSocketEx(SocketExHandler seh, int port, int backlog, InetAddress bindAddr ) throws IOException super(port,backlog, bindAddr);this.seh = seh;Listen();public void setTimeout(int timeout) this.timeout = timeout; public stati
23、c Vector GetClientPool()return ClientPool;public static void CloseAllClients()for(int i=0;i= 0) try sleeping = true; sleep(sleepTime); sleeping = false; catch (InterruptedException i) /Diagnostic.out.println(TIMER: Caught me napping); /* * Add a new task */ public void add(TimerClient client, int ev
24、entId, long delay, boolean repeat) TimerTask t = new TimerTask(client, eventId, delay, repeat); synchronized (tasks) tasks.addElement(Object)t); / Want instant response - wake the thread if its napping / unfortunately the interrupt() method is not working/ if (sleeping)/ interrupt(); if (suspended)
25、synchronized(this) notify(); /Diagnostic.out.println(TIMER: Resume); suspended = false; /* * Find the job and mark it for deletion */ public void end(TimerClient client, int eventId) synchronized (tasks) for (int i = 0; i tasks.size(); i+) TimerTask t = (TimerTask)tasks.elementAt(i); /if (!t.deleteP
26、ending & t.client = client & t.eventId = eventId) if (t.deletePending = false & t.client = client & t.eventId = eventId) / JPBS - if we dont reset repeat, deletePending will be set again t.repeat = false; t.deletePending = true; break; /* * Clear out all the dead wood */ void purge() for (int i = 0;
27、 i tasks.size(); i+) TimerTask t = (TimerTask)tasks.elementAt(i); if (t.deletePending) /Diagnostic.out.println(TIMER: purged); tasks.removeElementAt(i); i-; long scan() / The value added to the current time determines the MAX time until / the next scan / This is 100 now since errupt() is not impleme
28、nted long nextTime = System.currentTimeMillis() + 100; for (int i = 0; i = timeNext) /Diagnostic.out.println(TIMER: fire); / Fire the event client.timerEvent(eventId); / Update the next time timeNext = System.currentTimeMillis() + timeDelay; deletePending = !repeat; 下面是使用上面的異步socket類,做的demo開發(fā) DemoAp
29、pSocketHandler.java package ;import .*; import java.util.*;/* * Title: * Description: * Copyright: Copyright (c) 2001 * Company: * author dozb * version 1.0 */public interface DemoAppSocketHandler/當(dāng)客戶端sock有數(shù)據(jù)到達(dá)時(shí)觸發(fā)public void OnProcessCmd(Object socket,String FromArea,String ToArea,String ChannNo,Str
30、ing MainFun,String SubFun,Vector ParamList);/當(dāng)客戶端sock連接建立成功時(shí)觸發(fā)public void OnConnect(Object socket);/當(dāng)服務(wù)端sock監(jiān)聽開始時(shí)觸發(fā)public void OnListen(Object socket);/當(dāng)服務(wù)端sock接受一個(gè)新的sock連接時(shí)觸發(fā)public void OnAccept(Object socket,SocketEx ClientSocket) ;/當(dāng)sock關(guān)閉時(shí)觸發(fā)public void OnClose(Object socket);DemoAppSocket.java p
31、ackage ;import java.io.*;import java.util.*;import com.ly.util.*;/* * Title: * Description: * Copyright: Copyright (c) 2001 * Company: * author dozb * version 1.0 */這個(gè)類是異步socket 客戶端和服務(wù)端的使用演示/對于客戶端,實(shí)現(xiàn)了斷開后自動連接/這個(gè)類是SocketExHandler 和 TimerClient 接口的實(shí)現(xiàn)public class DemoAppSocket implements SocketExHandler
32、,TimerClient/Sock構(gòu)造函數(shù)public DemoAppSocket(DemoAppSocketHandler issh,boolean isServer,String ip,int port) this.issh = issh;this.isServer = isServer;this.ip = ip;if(this.ip = null) this.ip = ;this.port = port;if(this.port 0) this.port = 0; /調(diào)用完構(gòu)造后調(diào)用這個(gè)函數(shù)創(chuàng)建sock對象public void create() if(!start() TimerCtl
33、.startTimer(this,eventId,30*1000,true); /這個(gè)方法一般不需要直接調(diào)用 public boolean start() if(this.isServer) return startServer(); else return startClient(); /停止socket public void stop() TimerCtl.stopTimer(this,eventId);if(this.isServer) stopServer(); else stopClient(); /發(fā)送socket消息 public boolean SendCmd(Object
34、socket,String strCmd) SocketEx currSocketEx = (SocketEx)socket;if(!isServer & currSocketEx=null) currSocketEx = socketEx; if(currSocketEx = null) return false; try PrintWriter Sender = new PrintWriter(currSocketEx.getOutputStream(),true); Sender.print(strCmd); Sender.flush(); return true; catch(Exce
35、ption e) return false; /發(fā)送socket消息 public boolean SendCmd(Object socket,String FromArea,String ToArea,String ChannNo,String MainFun,String SubFun,String Param) String strCmd = FromArea + ToArea + ChannNo + MainFun+SubFun+&+Param+&;return SendCmd(socket,strCmd); /獲得IP地址 public String getIp() return i
36、p; /獲得端口號 public int getPort() return port; protected boolean startClient() if(socketEx != null) try socketEx.close(); catch(IOException e); socketEx = null; try socketEx = new SocketEx(this,ip,port); TimerCtl.stopTimer(this,eventId); return true; catch(IOException e) socketEx = null; return false;p
37、rotected boolean startServer() if(serverSocketEx != null) try serverSocketEx.close(); catch(IOException e); serverSocketEx = null; try serverSocketEx = new ServerSocketEx(this,port); TimerCtl.stopTimer(this,eventId); return true; catch(IOException e) serverSocketEx = null; return false;protected voi
38、d stopServer() if(serverSocketEx != null) try serverSocketEx.close(); catch(IOException e); serverSocketEx = null; protected void stopClient() if(socketEx != null) try socketEx.close(); catch(IOException e); socketEx = null; public void timerEvent(int id) start(); static public String DealStr(String
39、 strS) int CMDHEAD_LEN = 22; String ret = new String2;/0留下的字符串1完整的CMDret0=strS;/假如只有一個(gè)&或沒有&則不完整 int FirstPos=strS.indexOf(&); if(FirstPos=-1) return ret; if(FirstPos != CMDHEAD_LEN-1) strS = strS.substring(FirstPos+1); return DealStr(strS); int nSecondPos = strS.indexOf(&,FirstPos+1); if(nSecondPos0
40、) return ret; /可能格式不正確了 if(strS.length() CMDHEAD_LEN) return ret; ret1 = strS.substring(0,nSecondPos+1); ret0=strS.substring(nSecondPos+1); return ret; public void OnReceive(Object socket,byte buf,int nLen) String ReceiveBuff = sReceiveBuf + (new String(buf,0,nLen);do/分解成單個(gè)的命令串String strCmd = DealSt
41、r(ReceiveBuff);ReceiveBuff = strCmd0;if(strCmd1=null | strCmd1.equals() break;System.out.println(strCmd1);String FromArea=strCmd1.substring(0,6);String ToArea=strCmd1.substring(6,12);String ChannNo=strCmd1.substring(12,15);String MainFun=strCmd1.substring(15,18);String SubFun=strCmd1.substring(18,21
42、);String Param =strCmd1.substring(22,strCmd1.length()-1);Vector ParamList=new Vector();int nLastPos=0;while(true)int nPos = Param.indexOf(,nLastPos);if(nPos 0)ParamList.add(Param.substring(nLastPos);/System.out.println(Param.substring(nLastPos);break;String sParam = Param.substring(nLastPos,nPos);Pa
43、ramList.add(sParam);/System.out.println(sParam);nLastPos = nPos+1;DoProcessCmd(socket,FromArea,ToArea,ChannNo,MainFun,SubFun,ParamList);while(true);sReceiveBuf = ReceiveBuff;if(sReceiveBuf = null) sReceiveBuf=null; protected void DoProcessCmd(Object socket,String FromArea,String ToArea,String ChannN
44、o,String MainFun,String SubFun,Vector ParamList) if(issh !=null)issh.OnProcessCmd(socket,FromArea,ToArea,ChannNo,MainFun, SubFun, ParamList); public void OnConnect(Object socket) if(issh !=null) issh.OnConnect(socket);public void OnListen(Object socket) if(issh !=null) issh.OnListen(socket);public v
45、oid OnAccept(Object socket,SocketEx ClientSocket) if(issh !=null) issh.OnAccept(socket,ClientSocket);public void OnClose(Object socket)notifyAll(); TimerCtl.startTimer(this,eventId,30*1000,true);if(issh !=null) issh.OnClose(socket); /Socket SocketEx socketEx = null;ServerSocketEx serverSocketEx=null
46、; final int eventId = 1; String sReceiveBuf=;DemoAppSocketHandler issh=null;boolean isServer=false;String ip=;int port=20000;通過這種方式,可以高效地使用socket通訊,在異步socket版本沒有發(fā)布以前,不失是一種解決問題的方法。:)附錄資料:如何處理Java異常及常見異常六種異常處理的陋習(xí)你覺得自己是一個(gè)Java專家嗎?是否肯定自己已經(jīng)全面掌握了Java的異常處理機(jī)制?在下面這段代碼中,你能夠迅速找出異常處理的六個(gè)問題嗎? 1 OutputStreamWriter
47、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(ID: + rs.getString(uid) / 10 ,姓名: + rs.getString(name); 11 12 conn.close(); / 13 out.close(); 14 15 catch(Ex
48、ception ex) / 16 17 ex.printStackTrace(); /, 18 作為一個(gè)Java程序員,你至少應(yīng)該能夠找出兩個(gè)問題。但是,如果你不能找出全部六個(gè)問題,請繼續(xù)閱讀本文。 本文討論的不是Java異常處理的一般性原則,因?yàn)檫@些原則已經(jīng)被大多數(shù)人熟知。我們要做的是分析各種可稱為“反例”(anti-pattern)的違背優(yōu)秀編碼規(guī)范的常見壞習(xí)慣,幫助讀者熟悉這些典型的反面例子,從而能夠在實(shí)際工作中敏銳地察覺和避免這些問題。 反例之一:丟棄異常 代碼:15行-18行。 這段代碼捕獲了異常卻不作任何處理,可以算得上Java編程中的殺手。從問題出現(xiàn)的頻繁程度和禍害程度來看,它也
49、許可以和C/C+程序的一個(gè)惡名遠(yuǎn)播的問題相提并論?不檢查緩沖區(qū)是否已滿。如果你看到了這種丟棄(而不是拋出)異常的情況,可以百分之九十九地肯定代碼存在問題(在極少數(shù)情況下,這段代碼有存在的理由,但最好加上完整的注釋,以免引起別人誤解)。 這段代碼的錯(cuò)誤在于,異常(幾乎)總是意味著某些事情不對勁了,或者說至少發(fā)生了某些不尋常的事情,我們不應(yīng)該對程序發(fā)出的求救信號保持沉默和無動于衷。調(diào)用一下printStackTrace算不上“處理異?!?。不錯(cuò),調(diào)用printStackTrace對調(diào)試程序有幫助,但程序調(diào)試階段結(jié)束之后, printStackTrace就不應(yīng)再在異常處理模塊中擔(dān)負(fù)主要責(zé)任了。 丟棄異
50、常的情形非常普遍。打開JDK的ThreadDeath類的文檔,可以看到下面這段說明:“特別地,雖然出現(xiàn)ThreadDeath是一種正常的情形,但ThreadDeath類是Error而不是Exception的子類,因?yàn)樵S多應(yīng)用會捕獲所有的Exception然后丟棄它不再理睬?!边@段話的意思是,雖然ThreadDeath代表的是一種普通的問題,但鑒于許多應(yīng)用會試圖捕獲所有異常然后不予以適當(dāng)?shù)奶幚?,所以JDK把 ThreadDeath定義成了Error的子類,因?yàn)镋rror類代表的是一般的應(yīng)用不應(yīng)該去捕獲的嚴(yán)重問題??梢?,丟棄異常這一壞習(xí)慣是如此常見,它甚至已經(jīng)影響到了Java本身的設(shè)計(jì)。 那么,應(yīng)
51、該怎樣改正呢?主要有四個(gè)選擇: 1、處理異常。針對該異常采取一些行動,例如修正問題、提醒某個(gè)人或進(jìn)行其他一些處理,要根據(jù)具體的情形確定應(yīng)該采取的動作。再次說明,調(diào)用printStackTrace算不上已經(jīng)“處理好了異?!?。 2、重新拋出異常。處理異常的代碼在分析異常之后,認(rèn)為自己不能處理它,重新拋出異常也不失為一種選擇。 3、把該異常轉(zhuǎn)換成另一種異常。大多數(shù)情況下,這是指把一個(gè)低級的異常轉(zhuǎn)換成應(yīng)用級的異常(其含義更容易被用戶了解的異常)。 4、不要捕獲異常。 結(jié)論一:既然捕獲了異常,就要對它進(jìn)行適當(dāng)?shù)奶幚怼2灰东@異常之后又把它丟棄,不予理睬。 反例之二:不指定具體的異常 代碼:15行。 許多
52、時(shí)候人們會被這樣一種“美妙的”想法吸引:用一個(gè)catch語句捕獲所有的異常。最常見的情形就是使用catch(Exception ex)語句。但實(shí)際上,在絕大多數(shù)情況下,這種做法不值得提倡。為什么呢? 要理解其原因,我們必須回顧一下catch語句的用途。catch語句表示我們預(yù)期會出現(xiàn)某種異常,而且希望能夠處理該異常。異常類的作用就是告訴 Java編譯器我們想要處理的是哪一種異常。由于絕大多數(shù)異常都直接或間接從java.lang.Exception派生,catch (Exception ex)就相當(dāng)于說我們想要處理幾乎所有的異常。 再來看看前面的代碼例子。我們真正想要捕獲的異常是什么呢?最明顯的
53、一個(gè)是SQLException,這是JDBC操作中常見的異常。另一個(gè)可能的異常是IOException,因?yàn)樗僮鱋utputStreamWriter。顯然,在同一個(gè)catch塊中處理這兩種截然不同的異常是不合適的。如果用兩個(gè)catch塊分別捕獲SQLException和IOException就要好多了。這就是說,catch語句應(yīng)當(dāng)盡量指定具體的異常類型,而不應(yīng)該指定涵蓋范圍太廣的Exception類。 另一方面,除了這兩個(gè)特定的異常,還有其他許多異常也可能出現(xiàn)。例如,如果由于某種原因,executeQuery返回了null,該怎么辦?答案是讓它們繼續(xù)拋出,即不必捕獲也不必處理。實(shí)際上,我們
54、不能也不應(yīng)該去捕獲可能出現(xiàn)的所有異常,程序的其他地方還有捕獲異常的機(jī)會?直至最后由JVM處理。 結(jié)論二:在catch語句中盡可能指定具體的異常類型,必要時(shí)使用多個(gè)catch。不要試圖處理所有可能出現(xiàn)的異常。 反例之三:占用資源不釋放 代碼:3行-14行。 異常改變了程序正常的執(zhí)行流程。這個(gè)道理雖然簡單,卻常常被人們忽視。如果程序用到了文件、Socket、JDBC連接之類的資源,即使遇到了異常,也要正確釋放占用的資源。為此,Java提供了一個(gè)簡化這類操作的關(guān)鍵詞finally。 finally是樣好東西:不管是否出現(xiàn)了異常,F(xiàn)inally保證在try/catch/finally塊結(jié)束之前,執(zhí)行清
55、理任務(wù)的代碼總是有機(jī)會執(zhí)行。遺憾的是有些人卻不習(xí)慣使用finally。 當(dāng)然,編寫finally塊應(yīng)當(dāng)多加小心,特別是要注意在finally塊之內(nèi)拋出的異常?這是執(zhí)行清理任務(wù)的最后機(jī)會,盡量不要再有難以處理的錯(cuò)誤。 結(jié)論三:保證所有資源都被正確釋放。充分運(yùn)用finally關(guān)鍵詞。反例之四:不說明異常的詳細(xì)信息 代碼:3行-18行。 仔細(xì)觀察這段代碼:如果循環(huán)內(nèi)部出現(xiàn)了異常,會發(fā)生什么事情?我們可以得到足夠的信息判斷循環(huán)內(nèi)部出錯(cuò)的原因嗎?不能。我們只能知道當(dāng)前正在處理的類發(fā)生了某種錯(cuò)誤,但卻不能獲得任何信息判斷導(dǎo)致當(dāng)前錯(cuò)誤的原因。 printStackTrace的堆棧跟蹤功能顯示出程序運(yùn)行到當(dāng)前
56、類的執(zhí)行流程,但只提供了一些最基本的信息,未能說明實(shí)際導(dǎo)致錯(cuò)誤的原因,同時(shí)也不易解讀。 因此,在出現(xiàn)異常時(shí),最好能夠提供一些文字信息,例如當(dāng)前正在執(zhí)行的類、方法和其他狀態(tài)信息,包括以一種更適合閱讀的方式整理和組織printStackTrace提供的信息。 結(jié)論四:在異常處理模塊中提供適量的錯(cuò)誤原因信息,組織錯(cuò)誤信息使其易于理解和閱讀。 反例之五:過于龐大的try塊 代碼:3行-14行。 經(jīng)??梢钥吹接腥税汛罅康拇a放入單個(gè)try塊,實(shí)際上這不是好習(xí)慣。這種現(xiàn)象之所以常見,原因就在于有些人圖省事,不愿花時(shí)間分析一大塊代碼中哪幾行代碼會拋出異常、異常的具體類型是什么。把大量的語句裝入單個(gè)巨大的tr
57、y塊就象是出門旅游時(shí)把所有日常用品塞入一個(gè)大箱子,雖然東西是帶上了,但要找出來可不容易。 一些新手常常把大量的代碼放入單個(gè)try塊,然后再在catch語句中聲明Exception,而不是分離各個(gè)可能出現(xiàn)異常的段落并分別捕獲其異常。這種做法為分析程序拋出異常的原因帶來了困難,因?yàn)橐淮蠖未a中有太多的地方可能拋出Exception。 結(jié)論五:盡量減小try塊的體積。 反例之六:輸出數(shù)據(jù)不完整 代碼:7行-11行。 不完整的數(shù)據(jù)是Java程序的隱形殺手。仔細(xì)觀察這段代碼,考慮一下如果循環(huán)的中間拋出了異常,會發(fā)生什么事情。循環(huán)的執(zhí)行當(dāng)然是要被打斷的,其次, catch塊會執(zhí)行?就這些,再也沒有其他動作
58、了。已經(jīng)輸出的數(shù)據(jù)怎么辦?使用這些數(shù)據(jù)的人或設(shè)備將收到一份不完整的(因而也是錯(cuò)誤的)數(shù)據(jù),卻得不到任何有關(guān)這份數(shù)據(jù)是否完整的提示。對于有些系統(tǒng)來說,數(shù)據(jù)不完整可能比系統(tǒng)停止運(yùn)行帶來更大的損失。 較為理想的處置辦法是向輸出設(shè)備寫一些信息,聲明數(shù)據(jù)的不完整性;另一種可能有效的辦法是,先緩沖要輸出的數(shù)據(jù),準(zhǔn)備好全部數(shù)據(jù)之后再一次性輸出。 結(jié)論六:全面考慮可能出現(xiàn)的異常以及這些異常對執(zhí)行流程的影響。 改寫后的代碼 根據(jù)上面的討論,下面給出改寫后的代碼。也許有人會說它稍微有點(diǎn)?嗦,但是它有了比較完備的異常處理機(jī)制。 OutputStreamWriter out = . java.sql.Connecti
59、on conn = . try Statement stat = conn.createStatement(); ResultSet rs = stat.executeQuery( select uid, name from user); while (rs.next() out.println(ID: + rs.getString(uid) + ,姓名: + rs.getString(name); catch(SQLException sqlex) out.println(警告:數(shù)據(jù)不完整); throw new ApplicationException(讀取數(shù)據(jù)時(shí)出現(xiàn)SQL錯(cuò)誤, sqle
60、x); catch(IOException ioex) throw new ApplicationException(寫入數(shù)據(jù)時(shí)出現(xiàn)IO錯(cuò)誤, ioex); finally if (conn != null) try conn.close(); catch(SQLException sqlex2) System.err(this.getClass().getName() + .mymethod - 不能關(guān)閉數(shù)據(jù)庫連接: + sqlex2.toString(); if (out != null) try out.close(); catch(IOException ioex2) System.e
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 醫(yī)療大數(shù)據(jù)在治療方案選擇中的價(jià)值
- 護(hù)理員職業(yè)發(fā)展的試題及答案
- 安徽省民政廳直屬事業(yè)單位招聘考試真題2024
- 2024年重慶師范大學(xué)事業(yè)單位招聘筆試真題
- 2025年護(hù)師考試個(gè)體差異復(fù)習(xí)試題及答案
- 2024年棗莊東林農(nóng)文化產(chǎn)業(yè)發(fā)展有限公司招聘工作人員筆試真題
- 執(zhí)業(yè)醫(yī)師考試臨床決策能力測評試題及答案
- 行政法學(xué)考生指導(dǎo)試題與答案
- 經(jīng)濟(jì)法概論復(fù)習(xí)心得試題及答案
- 2025年主管護(hù)師考試關(guān)鍵成就試題及答案
- XX醫(yī)院核醫(yī)學(xué)應(yīng)急預(yù)案手冊
- 華為HCIP云計(jì)算H13-527認(rèn)證備考試題附答案
- 河南省漯河市2024-2025學(xué)年高三上學(xué)期期末質(zhì)量監(jiān)測語文試題及答案解析
- 血液透析中心可行性研究投資報(bào)告
- 舞蹈藝術(shù)賞析課件
- 《孔子的簡介》課件
- 2025年浙江省寧波市江北區(qū)行政服務(wù)中心招聘編外人員筆試和高頻重點(diǎn)提升(共500題)附帶答案詳解
- 非謂語動詞-動名詞和分詞
- 生產(chǎn)安全質(zhì)量培訓(xùn)
- 復(fù)工協(xié)議書模板
- 數(shù)列-2020-2024年高考數(shù)學(xué)試題分類匯編(原卷版)
評論
0/150
提交評論