Java編程中最容易忽略的問題_第1頁
Java編程中最容易忽略的問題_第2頁
Java編程中最容易忽略的問題_第3頁
Java編程中最容易忽略的問題_第4頁
Java編程中最容易忽略的問題_第5頁
已閱讀5頁,還剩4頁未讀, 繼續(xù)免費閱讀

下載本文檔

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

文檔簡介

1、Java編程中最容易忽略的問題1. 糾結(jié)的同名現(xiàn)象很多類的命名相同(例如:常見于異常、常量、日志等類),導(dǎo)致在import時,有時候張冠李戴,這種錯誤有時候很隱蔽。因為往往同名的類功能也類似,所以IDE不會提示warn。解決寫完代碼時,掃視下import部分,看看有沒有不熟悉的。替換成正確導(dǎo)入后,要注意下注釋是否也作相應(yīng)修改。啟示命名盡量避開重復(fù)名,特別要避開與JDK中的類重名,否則容易導(dǎo)入錯,同時存在大量重名類,在查找時,也需要更多的辨別時間。2. 想當(dāng)然的API現(xiàn)象有時候調(diào)用API時,會想當(dāng)然的通過名字直接自信滿滿地調(diào)用,導(dǎo)致很驚訝的一些錯誤:示例一:flag是true?boolean f

2、lag = Boolean.getBoolean("true");可能老是false。示例二:這是去年的今天嗎(今年是2012年,不考慮閏年)?結(jié)果還是2012年:Calendar calendar = GregorianCalendar.getInstance();calendar.roll(Calendar.DAY_OF_YEAR, -365);下面的才是去年:calendar.add(Calendar.DAY_OF_YEAR, -365);解決辦法問自己幾個問題,這個方法我很熟悉嗎?有沒有類似的API? 區(qū)別是什么?就示例一而言,需要區(qū)別的如下:Boolean.val

3、ueOf(b) VS Boolean.parseBoolean(b) VS Boolean.getBoolean(b);啟示名字起的更詳細點,注釋更清楚點,不要不經(jīng)了解、測試就想當(dāng)然的.用一些API,如果時間有限,用自己最為熟悉的API。3. 有時候溢出并不難現(xiàn)象有時候溢出并不難,雖然不常復(fù)現(xiàn):示例一:long x=Integer.MAX_VALUE+1;System.out.println(x);x是多少?竟然是-2147483648,明明加上1之后還是long的范圍。類似的經(jīng)常出現(xiàn)在時間計算:數(shù)字1×數(shù)字2×數(shù)字3示例二:在檢查是否為正數(shù)的參數(shù)校驗中,為了避免重載,選用

4、參數(shù)number, 于是下面代碼結(jié)果小于0,也是因為溢出導(dǎo)致:Number i=Long.MAX_VALUE;System.out.println(Value()>0);解決讓第一個操作數(shù)是long型,例如加上L或者l(不建議小寫字母l,因為和數(shù)字1太相似了);不確定時,還是使用重載吧,即使用doubleValue(),當(dāng)參數(shù)是BigDecimal參數(shù)時,也不能解決問題。啟示對數(shù)字運用要保持敏感:涉及數(shù)字計算就要考慮溢出;涉及除法就要考慮被除數(shù)是0;實在容納不下了可以考慮BigDecimal之類。4. 日志跑哪了?現(xiàn)象有時候覺得log都打了,怎么找不到?示例一:沒有stack

5、trace! catch (Exception ex) log.error(ex);示例二:找不到log! catch (ConfigurationException e) e.printStackTrace();解決替換成log.error(ex.getMessage(),ex);換成普通的log4j吧,而不是System.out。啟示API定義應(yīng)該避免讓人犯錯,如果多加個重載的log.error(Exception)自然沒有錯誤發(fā)生在產(chǎn)品代碼中,使用的一些方法要考慮是否有效,使用e.printStackTrace()要想下終端(Console)在哪。5. 遺忘的Volatile現(xiàn)象在DCL

6、模式中,總是忘記加一個Volatile。private static CacheImpl instance; /lose volatilepublic static CacheImpl getInstance() if (instance = null) synchronized (CacheImpl.class) if (instance = null) instance = new CacheImpl (); return instance;解決毋庸置疑,加上一個吧,synchronized 鎖的是一塊代碼(整個方法或某個代碼塊),保證的是這”塊“代碼的可見性及原子性,但是instance

7、 = null第一次判斷時不再范圍內(nèi)的。所以可能讀出的是過期的null。啟示我們總是覺得某些低概率的事件很難發(fā)生,例如某個時間并發(fā)的可能性、某個異常拋出的可能性,所以不加控制,但是如果可以,還是按照前人的“最佳實踐”來寫代碼吧。至少不用過多解釋為啥另辟蹊徑。6. 不要影響彼此現(xiàn)象在釋放多個IO資源時,都會拋出IOException ,于是可能為了省事如此寫:public static void inputToOutput(InputStream is, OutputStream os, boolean isClose) throws IOException BufferedInputStrea

8、m bis = new BufferedInputStream(is, 1024);BufferedOutputStream bos = new BufferedOutputStream(os, 1024);. if (isClose) bos.close();bis.close();假設(shè)bos關(guān)閉失敗,bis還能關(guān)閉嗎?當(dāng)然不能!解決辦法雖然拋出的是同一個異常,但是還是各自捕獲各的為好。否則第一個失敗,后一個面就沒有機會去釋放資源了。啟示代碼/模塊之間可能存在依賴,要充分識別對相互的依賴。7. 用斷言取代參數(shù)校驗現(xiàn)象如題所提,作為防御式編程常用的方式:斷言,寫在產(chǎn)品代碼中做參數(shù)校驗等。例如:

9、private void send(List< Event> eventList) assert eventList != null;解決換成正常的統(tǒng)一的參數(shù)校驗方法。因為斷言默認是關(guān)閉的,所以起不起作用完全在于配置,如果采用默認配置,經(jīng)歷了eventList != null結(jié)果還沒有起到作用,徒勞無功。啟示有的時候,代碼起不起作用,不僅在于用例,還在于配置,例如斷言是否啟用、log級別等,要結(jié)合真實環(huán)境做有用編碼。8. 用戶認知負擔(dān)有時候很重現(xiàn)象先來比較三組例子,看看那些看著更順暢?示例一:public void caller(int a, String b, float c,

10、String d) methodOne(d, z, b);methodTwo(b, c, d);public void methodOne(String d, float z, String b) public void methodTwo(String b, float c, String d)示例二:public boolean remove(String key, long timeout) Future< Boolean> future = memcachedClient.(key);public boolean (String key, long timeout) Fut

11、ure< Boolean> future = memcachedClient.(key);示例三:public static String getDigest(String filePath, DigestAlgorithm algorithm)public static String getDigest(String filePath, DigestAlgorithm digestAlgorithm)解決保持參數(shù)傳遞順序;remove變成了,顯得突兀了點, 統(tǒng)一表達更好;保持表達,少縮寫也會看起來流暢點。啟示在編碼過程中,不管是參數(shù)的順序還是命名都盡量統(tǒng)一,這樣用戶的認知負擔(dān)會很

12、少,不要要用戶容易犯錯或迷惑。例如用枚舉代替string從而不讓用戶迷惑到底傳什么string, 諸如此類。9. 忽視日志記錄時機、級別現(xiàn)象存在下面兩則示例:示例一:該不該記錄日志?catch (SocketException e)LOG.error("server error", e); throw new ConnectionException(e.getMessage(), e);示例二:記什么級別日志?在用戶登錄系統(tǒng)中,每次失敗登錄:LOG.warn("Failed to login by "+username+");解決移除日志記錄:

13、在遇到需要re-throw的異常時,如果每個人都按照先記錄后throw的方式去處理,那么對一個錯誤會記錄太多的日志,所以不推薦如此做;但是如果re-throw出去的exception沒有帶完整的trace( 即cause),那么最好還是記錄下。如果惡意登錄,那系統(tǒng)內(nèi)部會出現(xiàn)太多WARN,從而讓管理員誤以為是代碼錯誤??梢苑答佊脩粢藻e誤,但是不要記錄用戶錯誤的行為,除非想達到控制的目的。啟示日志改不改記?記成什么級別?如何記?這些都是問題,一定要根據(jù)具體情況,需要考慮:是用戶行為錯誤還是代碼錯誤?記錄下來的日志,能否能給別人在不造成過多的干擾前提下提供有用的信息以快速定位問題。10. 忘設(shè)初始容

14、量現(xiàn)象在JAVA中,我們常用Collection中的Map做Cache,但是我們經(jīng)常會遺忘設(shè)置初始容量。cache = new LRULinkedHashMap< K, V>(maxCapacity);解決初始容量的影響有多大?拿LinkedHashMap來說,初始容量如果不設(shè)置默認是16,超過16×LOAD_FACTOR,會resize(2 * table.length),擴大2倍:采用 Entry newTable = new EntrynewCapacity; transfer(newTable),即整個數(shù)組Copy, 那么對于一個需要做大容量CACHE來說,從16變成一個很大的數(shù)量,需要做多少次數(shù)組復(fù)制可想而知。如果初始容量就設(shè)置很大,自然會減少resize, 不過可能會擔(dān)心,初始容量設(shè)置很大時,沒有Cache內(nèi)容仍然會占用過大體積。其實可以參考以下表格簡單計算下, 初始時還沒有cache內(nèi)容, 每個對象僅僅是4字節(jié)引用而已。memory for reference fields (4 bytes each);memory for prim

溫馨提示

  • 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)容負責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論