閱讀324 返回首頁    go 阿裏雲 go 技術社區[雲棲]


《Java特種兵》1.6 常見的目錄與工具包

1.6 常見的目錄與工具包

很多做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類中,它們擁有非常多的對集合類和數組的操作動作,足以滿足絕大部分需求。下麵通過兩個場景給大家一點感性認識。

場景1:通過常量構造一個ArrayList返回。

最直接的寫法是:

List<String>list = new ArrayList<String>();
list.add("a");
list.add("b");
list.add("c");

用工具就可以這樣寫:

List<String> list = Arrays.asList("a" , "b" , "c");

或許你認為就是語法糖而已,而Java本身要的就是簡單,我們希望將更多的精力花在實際創造上,這樣的代碼可能會在係統中反反複複出現,其實很多時候是枯燥無味的。

場景2:中文拚音排序。

代碼片段1-6 一個簡單的中文拚音排序

public class SampleChineseSort {

	@SuppressWarnings("rawtypes")
	private final static Comparator CHINA_COMPARE
			= Collator.getInstance(java.util.Locale.CHINA);

	public static void main(String []args) {
		sortArray();
		sortList();
	}

	private static void sortList() {
		List<String>list = Arrays.asList("張三", "李四", "王五");
		Collections.sort(list , CHINA_COMPARE);
		for(String str : list) {
			System.out.println(str);
		}
	}

	private static void sortArray() {
		String[] arr = {"張三", "李四", "王五"};
		Arrays.sort(arr, CHINA_COMPARE);
		for(String str : arr) {
			System.out.println(str);
		}
	}
}

關於排序不僅僅如此,有些時候我們還需要用對象排序,對象怎麼排序呢?當然是基於對象內部某些自定義的屬性來排序了。而不論用什麼來做Java排序,都需要使用數字來排序,也就是要有大小關係。Java提供了Comparable和Comparator兩種接口(兩種接口是分開用的),Comparable接口需要讓列表中的對象來實現接口中的方法compareTo(E),返回正數表示當前對象比傳入對象大,當前對象會排序靠後;返回0表示等值,返回負數表示當前對象比傳入對象小,排序靠前。也就是你告訴Java對象之間的大小關係(而誰大誰小是你自己決定的),Java就會從小到大排列;如果想要反向排序,那麼就將返回值“取反”;如果想要按照多個字段排序,在這個方法內部也是可以完成的。

大家可能發現這樣的方式不是太靈活,因為一個對象實現接口後,這個方法就固定了。也就是說,它的排序算法已經固定了,如果它的排序算法不是固定的,是可以動態調整的,那麼就用Comparator接口來擴展,它獨立於被排序的對象單獨存在,當需要排序的時候,以參數的形式傳遞,上麵例子中的“CHINA_COMPARE”就是一個Comparator實例。你也可以自己實現一個自定義對象的排序方式來滿足特定對象的要求,如果同樣的對象一會想這樣排序,一會想那樣排序,就隻需要使用不同的Comparator實例即可。

 

這是一種基本的封裝思路,Java就是希望讓開發者關注更少的事情,它幫你去完成排序。這種思路也衍生到SortedSet中的排序,也在Timer、ScheduleThreadPool調度任務中使用(確切說是內部包裝的,在PriorityQueue中使用,5.6節會詳細闡述)。關於這些內容,可以參考胖哥的個人博客:https://blog.csdn.net/xieyuooo/article/details/8611198。

例子舉不完,Java本身提供的工具非常多,而且每個版本都會有新的工具包出現。除此之外,還有許多的二方包、三方包都提供了大量的工具類,這裏就不再逐個舉例了。Java是希望將一些複雜的邏輯細節封裝在工具中,讓業務代碼盡量幹淨、整潔,容易維護。反之,如果業務代碼中出現了大量的排序、字符串處理、日期處理、類型轉換、數組或集合類循環拷貝與組裝、文件處理、網絡IO等片段,我們就會感覺代碼“不幹淨”,這樣的代碼會在許多地方出現,這也意味著如果需要修改則要到許多地方去完成,而很多時候我們不知道到哪裏去修改。這些代碼會讓我們的思路不斷在技術和業務之間切換,沒法專心做好業務細節,更沒法深度挖掘業務。技術本身是在業務驅動下才能發揮作用的,而人在業務驅動下去學習技術是能得到最佳實踐的。

例如,Apache就提供了許多有用的三方包給我們使用,很多人都應該熟知StringUtils這個工具包吧,類似的還有很多,如upload、連接池、log4j、字符集處理等都可以算是工具包,這些工具包提供了大量API,大多數情況下無須自己去實現處理細節,因為它們的正確性和性能是經過很多公司驗證的,如果有問題大家都會知道。所以,我們在注重功底的基礎上也需要大量的學習,鋪開知識麵,才能有選擇,但“深知內在細節是我們量化選擇的條件”。

當然,不是所有的工具包都能完全滿足我們的需求,而往往“最煩人”的就是這個工具包滿足一部分需求,那個工具包滿足一部分需求,而將這些工具包組合起來使用可能比自己寫一個還麻煩,翻譯為基礎代碼還會有一大堆的冗餘,此時就可以考慮擴展了。

每個場景都會有一些變化,開源的工具僅僅是提供一些通用的處理,同時提供一種Java封裝思想,許多代碼也值得我們去參考。因此當遇到個性化問題的時候,並非別人沒提供自己就不寫了,個性化包裝就是一個優秀程序員需要去承擔的責任,所以老A程序員除了擁有非凡的功力外,也同時需要深知所涉及領域的業務和個性化,這樣才能針對業務做出一個“很爽”的架構體係。

胖哥說話好像在“繞圈”,怎麼又繞回功底來了?其實胖哥此處再談功底,是要說明在這個基礎上根據實際的場景應當“因地製宜”才能“事半功倍”,同時要以大量的知識麵為基礎,充分利用現有的資源。

最後更新:2017-05-23 14:02:29

  上一篇:go  Java IO: 流
  下一篇:go  Java IO: FileReader和FileWriter