Java項目開發(fā)代碼Review常見問題實例_第1頁
Java項目開發(fā)代碼Review常見問題實例_第2頁
Java項目開發(fā)代碼Review常見問題實例_第3頁
Java項目開發(fā)代碼Review常見問題實例_第4頁
Java項目開發(fā)代碼Review常見問題實例_第5頁
已閱讀5頁,還剩35頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認(rèn)領(lǐng)

文檔簡介

1、 Java項目開發(fā)CodeReview常見問題實例分析及指南第一章 綜述4第二章 常見問題分類及實例分析42.1 開發(fā)規(guī)范類4 命名規(guī)范4 代碼格式72.2 性能影響及系統(tǒng)穩(wěn)定性102.2.1 Java操作數(shù)據(jù)庫10 數(shù)據(jù)庫SQL開發(fā)注意事項14 數(shù)據(jù)庫存儲過程編寫17 Java編程方面192.3 編程易錯誤區(qū)及系統(tǒng)健壯性21 空指針錯誤的引發(fā)21 格式化數(shù)字錯誤22 字符串越界錯誤22 沒有克隆(clone)返回的對象22 不必要的克隆24 自編代碼來拷貝數(shù)組25 拷貝錯誤的數(shù)據(jù)26 檢查new 操作的結(jié)果是否為null28 用= 替代.equals28 混淆原子操作和非原子操作29 在ca

2、tch 塊中作清除工作30 增加不必要的catch 塊31 沒有正確實現(xiàn)equals,hashCode,或者clone 等方法312.4 Java編程不良習(xí)慣322.4.1 Servlet中獲取數(shù)據(jù)庫連接問題32 對于Exception的處理32 有關(guān)常量的使用33 靜態(tài)變量的使用33 未使用的變量33 過于龐大的try塊33 最好不要讓系統(tǒng)自己進行類型轉(zhuǎn)換362.5 ResourceOne開發(fā)框架使用問題36 在普通JavaClass中獲得數(shù)據(jù)庫連接362.5.2 Servlet中使用SearchDAO37 程序調(diào)試信息37 超長類名:使用R1Studio生成數(shù)據(jù)訪問類的問題37 代碼中直接

3、使用JDBC進行數(shù)據(jù)庫操作38 代碼的分包問題38 使用DAO操作時直接在Servlet里進行操作392.6 業(yè)務(wù)邏輯問題39 程序邏輯錯誤39第一章 綜述基礎(chǔ)技術(shù)資源開發(fā)與管理部在頒布六統(tǒng)一管理代碼review辦法中,從管理的角度對中軟國際所有的軟件開發(fā)項目的程序代碼review作了相關(guān)的要求,并且推行Jupiter這樣的CodeReview協(xié)同管理工具來輔助促進和跟蹤review的狀態(tài)和結(jié)果。CodeReview的基本手段還是需要技術(shù)經(jīng)理通過人工檢查項目成員的代碼,來將各種問題扼殺在開發(fā)階段,但是不同經(jīng)驗及技術(shù)水平的經(jīng)理在review同一段代碼所發(fā)現(xiàn)的問題可能相差比較大,不同的Team可能

4、因此產(chǎn)生的效果也不同。本文從實際項目中抽取了一些項目中常見的Java開發(fā)所涉及的問題,進行實例分析,為各技術(shù)經(jīng)理提供靶子和借鑒參考,如果審查者能夠有意識地尋找特定的錯誤,而不是靠漫無目的的瀏覽代碼來發(fā)現(xiàn)錯誤,那么代碼審查的效果會事半功倍如能做到舉一反三,則意義更大。第二章 常見問題分類及實例分析2.1 開發(fā)規(guī)范類在六統(tǒng)一規(guī)范中頒布的Java開發(fā)編碼規(guī)范和Delphi開發(fā)規(guī)范,里面都專門對于Java和Delphi語言進行開發(fā)的詳細(xì)規(guī)定。下面是對一些基本要求的重申,對于代碼review比較基礎(chǔ)和關(guān)鍵。2.1.1 命名規(guī)范 Java程序 .1 包名Ø具體的示例如

5、下:com.icss下面為平臺包。stmacmbas為本項目的根程序包。stmacmbas.base為本項目的開發(fā)基礎(chǔ)包merce為商業(yè)企業(yè)程序包stmacmbas.example為示例程序包stmacmbas.industry為工業(yè)企業(yè)程序包stmacmbas.stma為國家局程序包stmacmbas.util為工具包.2 文件名Ø 文件名由英文單詞組成,每個單詞的首字母大寫,最好不要超過4個單詞,如ShipOrder.java。Ø Java文件的文件名要與程序中的public類名相同。Ø Servet文件要以Servlet做為結(jié)尾,如AddCom

6、panyServlet.java.3 類名Ø 變量的名字必須用一個小寫字母開頭。后面的單詞用大寫字母開頭。.4 變量名Ø Class 變量的命名 :變量的名字必須用一個小寫字母開頭。后面的單詞用大寫字母開頭。 Ø Static Final 變量的命名 :Static Final 變量的名字應(yīng)該都大寫,并且指出完整含義。Ø 用有意義的名字命名變量 。首先,用完整的英語單詞或約定俗成的簡寫命名你的變量(不允許用漢語拼音),如: firstName,zipCodeØ 用復(fù)數(shù)命名collection類變量。collectio

7、n包括數(shù)組,vector等。命名時使用復(fù)數(shù): customers ,classmates.5 方法名Ø 方法的名字必須用一個小寫字母開頭。后面的單詞用大寫字母開頭。Ø 方法的名字要與該方法的用途相關(guān)。.6 參數(shù)名Ø 參數(shù)的命名 :參數(shù)的名字必須和變量的命名規(guī)范一致。 Ø 方法的參數(shù) :使用有意義的參數(shù)命名,如果可能的話,使用和要賦值的字段一樣的名字。 增刪改程序和頁面的調(diào)用關(guān)系和文件名AddOrderServer, SaveOrderServer, DeleteOrderServlet不需要頁面,其他有JSP頁面

8、的Servlet要與JSP文件名相對應(yīng)。OrderDetailServet對應(yīng)兩個JSP文件,EditOrder用于可編輯狀態(tài),ShowOrder用于不可編輯狀態(tài)。AddOrderServlet和SaveOrderServlet的返回頁面可以是List頁面,也可以是Detail頁面,如果當(dāng)前人已完成所有可進行的操作,則回到List頁面,如果未完成,則回到Detail頁面。 CSS為不同的部署功能應(yīng)用建產(chǎn)不同的CSS件,如建三個文件:stama.css, industry.css和commerce.css2.1.2 代碼格式 Java程序.1 文件頭&#

9、216; 版權(quán)信息 版權(quán)信息必須在 java 文件的開頭,比如:/* 類名* 日期* 修改記錄* Copyright ICSS 2003* All right reserved.*/其他不需要出現(xiàn)在 javadoc 的信息也可以包含在這里。Ø Package/Imports package 行要在 import 行之前,import 中標(biāo)準(zhǔn)的包名要在本地的包名之前,而且按照字母順序排列。如果 import 行中包含了同一個包中的不同子目錄,則應(yīng)該用 * 來處理。對于import語句,如果某一個包中引用的類不超過三個(包括三個),不允許用import xxx.*;格式。將import的

10、classes歸類,按順序羅列: a. Java標(biāo)準(zhǔn)類(java.*) b. Java擴充類(javax.*) c. 第三方類 d. 你的應(yīng)用程序的類.2 縮進縮進應(yīng)該是每行4個空格,不要在源文件中保存Tab字符。 在使用不同的源代碼管理工具時Tab字符將因為用戶設(shè)置的不同而擴展為不同的寬度。.3 注釋為保證開發(fā)后JAVA DOC的順利生成,開發(fā)人員必須在所有方法,全局變量前加入加上標(biāo)準(zhǔn)JAVA注釋。類注釋需要包含以下要素:1 方法描述2 參數(shù): param 參數(shù)名 說明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 頁寬頁寬應(yīng)該設(shè)置為80字符, 源代碼一般不會超過這個寬度, 并導(dǎo)致無法完整顯示, 但這一設(shè)置也可以靈活調(diào)整。 在任何情況下, 超長的語句應(yīng)該在一個逗號或者一個操作符后折行, 一條語句折行后, 應(yīng)該比原來的語句再縮進2個字符。 HTML/JSP.1 文件頭文件頭要寫明該文件的用途,及修改記錄。如:<!

12、文件名:OrderList.jsp 說明:訂單列表 修改記錄:2003-08-24,張三,增加一個按鈕à.2 縮進HTML標(biāo)記層次之間的縮進為2個字符,Java代碼的縮進為4個字符,文件中不要有Tab符號,都要替換為空格。2.2 性能影響及系統(tǒng)穩(wěn)定性相關(guān)2.2.1 Java操作數(shù)據(jù)庫 Connection數(shù)據(jù)庫連接未關(guān)閉 嚴(yán)重級別:嚴(yán)重 1、問題造成的后果數(shù)據(jù)庫連接池中的數(shù)據(jù)庫連接被耗盡,新的獲取數(shù)據(jù)庫連接的請求進入等待狀態(tài),由于數(shù)據(jù)庫請求來自一個Servlet線程,因此造成請求的Servlet線程進入等待狀態(tài)。這也會造成Apache的Http服務(wù)器的客戶

13、端并發(fā)連接數(shù)打量增加。此時,訪問引用的首頁面會出現(xiàn)白頁現(xiàn)象。需要重新啟動WebSphere才能恢復(fù)對應(yīng)用的訪問。2、解決的方法Connection conn = null;try /處理業(yè)務(wù)邏輯 catch(SQLException) e.printstacktrace(); finally /在finally中關(guān)閉數(shù)據(jù)庫連接if(conn!=null) try conn.close(); catch(SQLException e) e.printstacktrace(); Statement/ResultSet未關(guān)閉問題嚴(yán)重級別:一般 n 問題代碼:程序中典型的未關(guā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中關(guān)閉數(shù)據(jù)庫連接if(conn!=null) try conn.close(); catch(SQLExcep

15、tion e) e.printstacktrace(); Statement對象未關(guān)閉積累到一定程度會造成執(zhí)行SQL語句時拋出SQLExceptionn 解決方法:首先要在try程序段中獲取Statement對象,這需要在try段外聲明Statement對象,然后在finally程序段中關(guān)閉獲取的Statement對象。Connection conn = null;Statement stmt = null;try stmt = conn.createStatement();/處理業(yè)務(wù)邏輯 catch(SQLException) e.printstacktrace(); finally /在f

16、inally中關(guān)閉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對象上也都存在,都需要在調(diào)用結(jié)束后關(guān)閉獲取的資源。 數(shù)據(jù)庫事務(wù)的使用嚴(yán)重級別:嚴(yán)重 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 正確做法:邏輯上對于批量業(yè)務(wù)的處理,會設(shè)計到多個數(shù)據(jù)庫表的操作,當(dāng)需要保證一次業(yè)務(wù)的完整性時,應(yīng)當(dāng)引入事務(wù)處理機制。即首先將Connnection的autoCommit屬性設(shè)置為false(默認(rèn)為true),保證全部業(yè)務(wù)執(zhí)行成功后,再調(diào)用Connection的commit()方法一次提交;如果中途出現(xiàn)異常,則調(diào)用Connectio

20、n的rollback()方法進行回滾。 超長事務(wù)和死鎖嚴(yán)重級別:嚴(yán)重 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 正確做法在程序中使用事務(wù)對數(shù)據(jù)庫操作進行加鎖,一定要注意盡量縮短事務(wù)段的時間,否則會引起系統(tǒng)性能下降甚至導(dǎo)致數(shù)據(jù)庫死鎖。事務(wù)段內(nèi)的操作只應(yīng)該是進行事務(wù)保護的相關(guān)數(shù)據(jù)操作的代碼,涉及查詢及其他無關(guān)的代碼都應(yīng)當(dāng)剝離出去。剛才這段代碼的conn.setAutoCommit(false);語句應(yīng)當(dāng)往后放,只在事務(wù)保護的數(shù)據(jù)操作開始之前,并且在數(shù)據(jù)操作完成

26、后立即進行事務(wù)提交mit()來盡早釋放數(shù)據(jù)庫鎖。2.2.2 數(shù)據(jù)庫SQL開發(fā)注意事項 IS NULL 與 IS NOT NULL 不能用null作索引,任何包含null值的列都將不會被包含在索引中。即使索引有多列這樣的情況下,只要這些列中有一列含有null,該列就會從索引中排除。也就是說如果某列存在空值,即使對該列建索引也不會提高性能。 任何在where子句中使用is null或is not null的語句優(yōu)化器是不允許使用索引的。 聯(lián)接列 對于有聯(lián)接的列,即使最后的聯(lián)接值為一個靜態(tài)值,優(yōu)化器是不會使用索引的。例如:假定有一個職工表(employee),對于一個職

27、工的姓和名分成兩列存放(FIRST_NAME和LAST_NAME),現(xiàn)在要查詢一個叫比爾.克林頓(Bill Cliton)的職工。 下面是一個采用聯(lián)接查詢的SQL語句, select * from employss where first_name|''|last_name ='Beill Cliton' 上面這條語句完全可以查詢出是否有Bill Cliton這個員工,但是這里需要注意,系統(tǒng)優(yōu)化器對基于last_name創(chuàng)建的索引沒有使用。 當(dāng)采用下面這種SQL語句的編寫,在Oracle系統(tǒng)中就可以采用基于last_name創(chuàng)建的索引。 Select * fro

28、m employee where first_name ='Beill' and last_name ='Cliton' 遇到下面這種情況又如何處理呢?如果一個變量(name)中存放著Bill Cliton這個員工的姓名,對于這種情況又如何避免全程遍歷,使用索引呢?可以使用一個函數(shù),將變量name中的姓和名分開就可以了,但是有一點需要注意,這個函數(shù)是不能作用在索引列上。下面是SQL查詢腳本: select * from employee where first_name = SUBSTR('&&name',1,INSTR('

29、;&&name',' ')-1) and last_name = SUBSTR('&&name',INSTR('&&name,' ')+1) 帶通配符(%)的like語句 同樣以上面的例子來看這種情況。目前的需求是這樣的,要求在職工表中查詢名字中包含cliton的人??梢圆捎萌缦碌牟樵僑QL語句: select * from employee where last_name like '%cliton%' 這里由于通配符(%)在搜尋詞首出現(xiàn),在Orac

30、le系統(tǒng)不使用last_name的索引。在很多情況下可能無法避免這種情況,但是一定要心中有底,通配符如此使用會降低查詢速度。然而當(dāng)通配符出現(xiàn)在字符串其他位置時,優(yōu)化器就能利用索引。在下面的查詢中索引得到了使用: select * from employee where last_name like 'c%' Order by語句 ORDER BY語句決定了如何將返回的查詢結(jié)果排序。Order by語句對要排序的列沒有什么特別的限制,也可以將函數(shù)加入列中(象聯(lián)接或者附加等)。任何在Order by語句的非索引項或者有計算表達(dá)式都將降低查詢速度。 仔細(xì)檢查order

31、 by語句以找出非索引項或者表達(dá)式,它們會降低性能。解決這個問題的辦法就是重寫order by語句以使用索引,也可以為所使用的列建立另外一個索引,同時應(yīng)絕對避免在order by子句中使用表達(dá)式。 NOT 我們在查詢時經(jīng)常在where子句使用一些邏輯表達(dá)式,如大于、小于、等于以及不等于等等,也可以使用and(與)、or(或)以及not(非)。NOT可用來對任何邏輯運算符號取反。下面是一個NOT子句的例子: . where not (status ='VALID') 如果要使用NOT,則應(yīng)在取反的短語前面加上括號,并在短語前面加上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; 雖然這兩種查詢的結(jié)果一樣,但是第二種查詢方案會比第一種查詢方案更快些。第二種查詢允許對s

33、alary列使用索引,而第一種查詢則不能使用索引。 IN和EXISTS 有時候會將一列和一系列值相比較。最簡單的辦法就是在where子句中使用子查詢。在where子句中可以使用兩種格式的子查詢。 第一種格式是使用IN操作符: . where column in(select * from . where .); 第二種格式是使用EXIST操作符: . where exists (select 'X' from .where .); 相信絕大多數(shù)人會使用第一種格式,因為它比較容易編寫,而實際上第二種格式要遠(yuǎn)比第一種格式的效率高。在常見數(shù)據(jù)庫中可以幾乎將所有的IN操

34、作符子查詢改寫為使用EXISTS的子查詢。 第二種格式中,子查詢以select 'X'開始。運用EXISTS子句不管子查詢從表中抽取什么數(shù)據(jù)它只查看where子句。這樣優(yōu)化器就不必遍歷整個表而僅根據(jù)索引就可完成工作(這里假定在where語句中使用的列存在索引)。相對于IN子句來說,EXISTS使用相連子查詢,構(gòu)造起來要比IN子查詢困難一些。 通過使用EXIST,數(shù)據(jù)庫系統(tǒng)會首先檢查主查詢,然后運行子查詢直到它找到第一個匹配項,這就節(jié)省了時間。在執(zhí)行IN子查詢時,首先執(zhí)行子查詢,并將獲得的結(jié)果列表存放在在一個加了索引的臨時表中。在執(zhí)行子查詢之前,系統(tǒng)先將主查詢掛起,待子查詢執(zhí)行完

35、畢,存放在臨時表中以后再執(zhí)行主查詢。這也就是使用EXISTS比使用IN通常查詢速度快的原因。 同時應(yīng)盡可能使用NOT EXISTS來代替NOT IN,盡管二者都使用了NOT(不能使用索引而降低速度),NOT EXISTS要比NOT IN查詢效率更高。2.2.3 數(shù)據(jù)庫存儲過程編寫 建立本庫視圖開發(fā)人員如果用到其他庫的Table或View,務(wù)必在當(dāng)前庫中建立View來實現(xiàn)跨庫操作,最好不要直接使用“databse.dbo.table_name”,因為sp_depends不能顯示出該SP所使用的跨庫table或view,不方便校驗。 存儲過程中SQL的使用1、 盡量避免

36、大事務(wù)操作,慎用holdlock子句,提高系統(tǒng)并發(fā)能力。2、 盡量避免反復(fù)訪問同一張或幾張表,尤其是數(shù)據(jù)量較大的表,可以考慮先根據(jù)條件提取數(shù)據(jù)到臨時表中,然后再做連接。 3、 盡量避免使用游標(biāo),因為游標(biāo)的效率較差,如果游標(biāo)操作的數(shù)據(jù)超過1萬行,那么就應(yīng)該改寫;如果使用了游標(biāo),就要盡量避免在游標(biāo)循環(huán)中再進行表連接的操作。 4、 注意where字句寫法,必須考慮語句順序,應(yīng)該根據(jù)索引順序、范圍大小來確定條件子句的前后順序,盡可能的讓字段順序與索引順序相一致,范圍從大到小。 5、 不要在where子句中的“=”左邊進行函數(shù)、算術(shù)運算或其他表達(dá)式運算,否則系統(tǒng)將可能無法正確使用索引。 6、 盡量使用e

37、xists代替select count(1)來判斷是否存在記錄,count函數(shù)只有在統(tǒng)計表中所有行數(shù)時使用,而且count(1)比count(*)更有效率。 7、 盡量使用“>=”,不要使用“>”。 8、 注意一些or子句和union子句之間的替換 9、 注意表之間連接的數(shù)據(jù)類型,避免不同類型數(shù)據(jù)之間的連接。 10、 注意存儲過程中參數(shù)和數(shù)據(jù)類型的關(guān)系。 11、 注意insert、update操作的數(shù)據(jù)量,防止與其他應(yīng)用沖突。如果數(shù)據(jù)量超過200個數(shù)據(jù)頁面(400k),那么系統(tǒng)將會進行鎖升級,頁級鎖會升級成表級鎖。 索引的使用 1、 索引的創(chuàng)建要與應(yīng)用結(jié)合考慮,建議

38、大的OLTP表不要超過6個索引。 2、 盡可能的使用索引字段作為查詢條件,尤其是聚簇索引,必要時可以通過index index_name來強制指定索引 3、 避免對大表查詢時進行table scan,必要時考慮新建索引。 4、 在使用索引字段作為條件時,如果該索引是聯(lián)合索引,那么必須使用到該索引中的第一個字段作為條件時才能保證系統(tǒng)使用該索引,否則該索引將不會被使用。 5、 要注意索引的維護,周期性重建索引,重新編譯存儲過程。 tempdb的使用1、 盡量避免使用distinct、order by、group by、having、join、cumpute,因為這些語句會加重tem

39、pdb的負(fù)擔(dān)。 2、 避免頻繁創(chuàng)建和刪除臨時表,減少系統(tǒng)表資源的消耗。 3、 在新建臨時表時,如果一次性插入數(shù)據(jù)量很大,那么可以使用select into代替create table,避免log,提高速度;如果數(shù)據(jù)量不大,為了緩和系統(tǒng)表的資源,建議先create table,然后insert。 4、 如果臨時表的數(shù)據(jù)量較大,需要建立索引,那么應(yīng)該將創(chuàng)建臨時表和建立索引的過程放在單獨一個子存儲過程中,這樣才能保證系統(tǒng)能夠很好的使用到該臨時表的索引。 5、 如果使用到了臨時表,在存儲過程的最后務(wù)必將所有的臨時表顯式刪除,先truncate table,然后drop table,這樣可以避免系統(tǒng)表的

40、較長時間鎖定。 6、 慎用大的臨時表與其他大表的連接查詢和修改,減低系統(tǒng)表負(fù)擔(dān),因為這種操作會在一條語句中多次使用tempdb的系統(tǒng)表。 合理的算法使用: 結(jié)合實際應(yīng)用,采用多種算法進行比較,以獲得消耗資源最少、效率最高的方法。具體可用ASE調(diào)優(yōu)命令:set statistics io on, set statistics time on , set showplan on 等。2.2.4 Java編程方面 InputStream/OutputStream未關(guān)閉問題嚴(yán)重級別:嚴(yán)重1、問題造成的后果對文件對象構(gòu)造的InputStream/OutputStream對象

41、未關(guān)閉會造成在同一段程序中調(diào)用File.delete()方法刪除同一個文件時刪除失敗的情況。2、解決的方法在對InputStream/OutputStream對象使用完畢后需要顯式的關(guān)閉流對象。為了防止在程序執(zhí)行過程中出現(xiàn)異常造成流對象無法關(guān)閉的情況,也可以在finally段中關(guān)閉流對象。 資源使用完成的釋放方式嚴(yán)重級別:嚴(yán)重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對象使用完畢后,應(yīng)當(dāng)顯式的進行關(guān)閉,釋放資源;第二種情況,應(yīng)當(dāng)在 Statement和ResultSet用完后,在finally代碼塊中顯式的關(guān)閉資源。 多次拷貝字符串嚴(yán)重級別:普通通常測試所不能發(fā)現(xiàn)的一個錯誤是生成不可變(immutable)對象的多份拷貝。不可變對象是不可

45、改變的,因此不需要拷貝它。最常用的不可變對象是String。如果你必須改變一個String對象的內(nèi)容,你應(yīng)該使用StringBuffer。下面的代碼會正常工作: String s = new String ("Text here"); 但是,這段代碼性能差,而且沒有必要這么復(fù)雜。你還可以用以下的方式來重寫上面的代碼: String temp = "Text here" String s = new String (temp); 但是這段代碼包含額外的String,并非完全必要。更好的代碼為: String s = "Text here"

46、; 第三種情況,應(yīng)當(dāng)在數(shù)據(jù)鏈接用完后,在finally代碼塊中顯式的關(guān)閉。 避免太多的使用 synchronized 關(guān)鍵字 嚴(yán)重級別:嚴(yán)重避免不必要的使用關(guān)鍵字 synchronized,應(yīng)該在必要的時候再使用她,這是一個避免死鎖的好方法。 字符串操作盡量使用 StringBuffer 對象嚴(yán)重級別:低在處理 String 的時候要盡量使用 StringBuffer 類,StringBuffer 類是構(gòu)成 String 類的基礎(chǔ)。String 類將 StringBuffer 類封裝了起來,(以花費更多時間為代價)為開發(fā)人員提供了一個安全的接口。當(dāng)我們在構(gòu)造字符串

47、的時候,我們應(yīng)該用 StringBuffer 來實現(xiàn)大部分的工作,當(dāng)工作完成后將 StringBuffer 對象再轉(zhuǎn)換為需要的 String 對象。比如:如果有一個字符串必須不斷地在其后添加許多字符來完成構(gòu)造,那么我們應(yīng)該使用 StringBuffer 對象和她的 append() 方法。如果我們用 String 對象代替 StringBuffer 對象的話,會花費許多不必要的創(chuàng)建和釋放對象的 CPU 時間。2.3 編程易錯誤區(qū)及系統(tǒng)健壯性2.3.1 空指針錯誤的引發(fā)嚴(yán)重級別:嚴(yán)重n 問題代碼:out.println(request.getParameter("username&qu

48、ot;);n 正確做法:使用基本的JAVA數(shù)據(jù)類型,變量的值要么已經(jīng)是默認(rèn)值,如果沒有對其正常賦值,程序便不能通過編譯,因此使用基本的JAVA數(shù)據(jù)類型(double,float,boolean,char,int,long)一般不會引起空指針異常。由此可見,空指針異常主要跟與對象的操作相關(guān)??瓷先?,上面的語句找不出什么語法錯誤,而且在大多數(shù)情況下也遇不到什么問題。但是,如果某個用戶在輸入數(shù)據(jù)時并沒有提供表單域"username"的值,或通過某種途徑繞過表單直接輸入時,此時request.getParameter("username")的值為空(不是空字符串

49、,是空對象null),out對象的println方法是無法直接對空對象操作,因此將會拋出java.lang.NullPointerException異常。2.3.2 格式化數(shù)字錯誤嚴(yán)重級別:普通n 問題代碼:String s_memberid = request.getParameter("memberid"); int i_memberid = Integer.parseInt(s_memberid);n 正確做法:如果用戶輸入正確的數(shù)字如:1082,不會有什么問題。然而,如果用戶輸入T1082時,由于T1082不是合法的數(shù)字格式,Java無法將其轉(zhuǎn)化為合適的數(shù)字,導(dǎo)致拋

50、出java.lang.NumberFormatException數(shù)字格式化異常。在任何用到字符串轉(zhuǎn)化為數(shù)字時,捕捉異常,對異常情況進行處理。這樣,在編程時稍微麻煩一點,但可以保證模塊更加健壯。2.3.3 字符串越界錯誤嚴(yán)重級別:普通n 問題代碼:String s_all_power = "1010011" tring s_access_power = s_all_power.substring(3,4);n 正確做法:一般情況下,程序不會有問題,如果由于某種原因,s_all_power長度變短,程序就會拋出字符串錯誤。所以,對字符串進行截取(substring, charA

51、t)、轉(zhuǎn)換為字節(jié)數(shù)組(getBytes)、字符數(shù)組轉(zhuǎn)換為字符串(valueOf)等操作時,應(yīng)當(dāng)先對操作字符串對象的存在性(是否為空)及長度進行檢查后,再進行操作。2.3.4 沒有克隆(clone)返回的對象嚴(yán)重級別:普通封裝(encapsulation)是面向?qū)ο缶幊痰闹匾拍?。不幸的是,Java為不小心打破封裝提供了方便Java允許返回私有數(shù)據(jù)的引用(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值永遠(yuǎn)非負(fù)數(shù),試圖使用setValues()方法來設(shè)置負(fù)值會觸發(fā)異常。不幸的是,由于getValues()返回d的引用,而不是d的拷貝,你可以編寫如下的破壞性代碼: Example ex = new Example(); Dimension d = ex.getValue

54、s(); d.height = -5; d.width = -10; 現(xiàn)在,Example對象擁有負(fù)值了!如果getValues() 的調(diào)用者永遠(yuǎn)也不設(shè)置返回的Dimension對象的width 和height值,那么僅憑測試是不可能檢測到這類的錯誤。不幸的是,隨著時間的推移,客戶代碼可能會改變返回的Dimension對象的值,這個時候,追尋錯誤的根源是件枯燥且費時的事情,尤其是在多線程環(huán)境中。更好的方式是讓getValues()返回拷貝: public synchronized Dimension getValues() return new Dimension (d.x, d.y); 現(xiàn)在,Example對象的內(nèi)部狀態(tài)就安全了。調(diào)用者可以根據(jù)需要改變它所得到的拷貝的狀態(tài),但是要修改Example對象的內(nèi)部狀態(tài),必須通過setValues()才可以。2.3.5 不必要的克隆嚴(yán)重級別:普通我們現(xiàn)在知道了get方法應(yīng)該返回內(nèi)部數(shù)據(jù)對象的拷貝,而不是引用。但是,事情沒有絕對: /* 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. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(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)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論