很多做java開發的同學們,在達到一定程度後,開始“身手不凡”,成為大俠,在了解了底層後,開始自己寫東西。這個階段容易糾結的就是重複制造,在了解了底層後我們需要提升知識面,知道哪些是别人提供的,哪些是需要我們自己寫的。
java的三方包無窮無盡,無法一一列舉這些工具包,但是我們應當知道有許多别人寫好的工具包可以直接拿來使用,以及如何來尋找這些工具包,基礎知識可以幫助我們快速學習新的工具包,以及掌握它的本質。同時,這裡的内容也算是為“源碼篇”做一個簡單鋪墊。
首先,要知道java本身提供的一些源碼放在哪裡。一般來講,安裝完jdk後,在jdk的根目錄下會有一個叫“src.zip”的壓縮包,解壓後是一個目錄,其中包含了常見的java源碼,但是以sun開頭的文章是找不到的,你可以通過一些反編譯手段得到,也可以在openjdk上找到一些源碼,主要目的是看懂意思和知道它的坑。
有工具後,從哪裡開始看起?從我們用到的api看起,當你需要用到某個api的時候,就可以檢視是否有相關的api,簡單記錄下來。看看是否有更好的方式,要有個大緻的筆記。例如,對于list的簡單使用,小胖哥問幾個小問題。
◎ 将arraylist轉換為linkedlist用什麼方法?各自的好壞?
◎ 将集合類、數組做一次淺拷貝用什麼方法?用for循環還是别的方法?
◎ 對list、數組做排序用什麼方法?
其實在對集合類、數組操作上,有一些java本身提供的工具類(靜态工具方法),分别位于java.util.collections、java.util.arrays類中,它們擁有非常多的對集合類和數組的操作動作,足以滿足絕大部分需求。下面通過兩個場景給大家一點感性認識。
最直接的寫法是:
用工具就可以這樣寫:
或許你認為就是文法糖而已,而java本身要的就是簡單,我們希望将更多的精力花在實際創造上,這樣的代碼可能會在系統中反反複複出現,其實很多時候是枯燥無味的。
代碼片段1-6 一個簡單的中文拼音排序
關于排序不僅僅如此,有些時候我們還需要用對象排序,對象怎麼排序呢?當然是基于對象内部某些自定義的屬性來排序了。而不論用什麼來做java排序,都需要使用數字來排序,也就是要有大小關系。java提供了comparable和comparator兩種接口(兩種接口是分開用的),comparable接口需要讓清單中的對象來實作接口中的方法compareto(e),傳回正數表示目前對象比傳入對象大,目前對象會排序靠後;傳回0表示等值,傳回負數表示目前對象比傳入對象小,排序靠前。也就是你告訴java對象之間的大小關系(而誰大誰小是你自己決定的),java就會從小到大排列;如果想要反向排序,那麼就将傳回值“取反”;如果想要按照多個字段排序,在這個方法内部也是可以完成的。
大家可能發現這樣的方式不是太靈活,因為一個對象實作接口後,這個方法就固定了。也就是說,它的排序算法已經固定了,如果它的排序算法不是固定的,是可以動态調整的,那麼就用comparator接口來擴充,它獨立于被排序的對象單獨存在,當需要排序的時候,以參數的形式傳遞,上面例子中的“china_compare”就是一個comparator執行個體。你也可以自己實作一個自定義對象的排序方式來滿足特定對象的要求,如果同樣的對象一會想這樣排序,一會想那樣排序,就隻需要使用不同的comparator執行個體即可。
這是一種基本的封裝思路,java就是希望讓開發者關注更少的事情,它幫你去完成排序。這種思路也衍生到sortedset中的排序,也在timer、schedulethreadpool排程任務中使用(确切說是内部包裝的,在priorityqueue中使用,5.6節會詳細闡述)。關于這些内容,可以參考胖哥的個人部落格:http://blog.csdn.net/xieyuooo/article/details/8611198。
例子舉不完,java本身提供的工具非常多,而且每個版本都會有新的工具包出現。除此之外,還有許多的二方包、三方包都提供了大量的工具類,這裡就不再逐個舉例了。java是希望将一些複雜的邏輯細節封裝在工具中,讓業務代碼盡量幹淨、整潔,容易維護。反之,如果業務代碼中出現了大量的排序、字元串處理、日期處理、類型轉換、數組或集合類循環拷貝與組裝、檔案處理、網絡io等片段,我們就會感覺代碼“不幹淨”,這樣的代碼會在許多地方出現,這也意味着如果需要修改則要到許多地方去完成,而很多時候我們不知道到哪裡去修改。這些代碼會讓我們的思路不斷在技術和業務之間切換,沒法專心做好業務細節,更沒法深度挖掘業務。技術本身是在業務驅動下才能發揮作用的,而人在業務驅動下去學習技術是能得到最佳實踐的。
例如,apache就提供了許多有用的三方包給我們使用,很多人都應該熟知stringutils這個工具包吧,類似的還有很多,如upload、連接配接池、log4j、字元集處理等都可以算是工具包,這些工具包提供了大量api,大多數情況下無須自己去實作處理細節,因為它們的正确性和性能是經過很多公司驗證的,如果有問題大家都會知道。是以,我們在注重功底的基礎上也需要大量的學習,鋪開知識面,才能有選擇,但“深知内在細節是我們量化選擇的條件”。
當然,不是所有的工具包都能完全滿足我們的需求,而往往“最煩人”的就是這個工具包滿足一部分需求,那個工具包滿足一部分需求,而将這些工具包組合起來使用可能比自己寫一個還麻煩,翻譯為基礎代碼還會有一大堆的備援,此時就可以考慮擴充了。
每個場景都會有一些變化,開源的工具僅僅是提供一些通用的處理,同時提供一種java封裝思想,許多代碼也值得我們去參考。是以當遇到個性化問題的時候,并非别人沒提供自己就不寫了,個性化包裝就是一個優秀程式員需要去承擔的責任,是以老a程式員除了擁有非凡的功力外,也同時需要深知所涉及領域的業務和個性化,這樣才能針對業務做出一個“很爽”的架構體系。
胖哥說話好像在“繞圈”,怎麼又繞回功底來了?其實胖哥此處再談功底,是要說明在這個基礎上根據實際的場景應當“因地制宜”才能“事半功倍”,同時要以大量的知識面為基礎,充分利用現有的資源。