瓜娃之走馬觀花 (1) - List和Map

[b]序[/b]

花開花落,花落花開。少年子弟江湖老,紅顏少女的兒子都會打醬油反三俗了.

驀然回首, 那個彷彿剛剛還在上幼兒園, 拉着我的手讓我帶着到麥當勞買雞塊冰激凌吃的小屁孩兒; 上了小學, 抱着我給買的盜版commando苦苦鑽研攻略的小表弟, 開始寫java程序了!

暑假去小表弟學校宿舍晃了一下. 書桌上隨手堆着的可樂礦泉水瓶; 書桌下凌亂的鞋子, 鼠標; 寢室門上的個性標語; 隔壁在炎夏裏半裸着看片子(木有看清是女主是否半裸)的猥瑣男生, 都讓俺情不自禁地小資起來: 唉, 世界是你們的了!

唯一地遺憾是沒有重溫一下女生寢室的風光 --- 上了年紀了, jailbreak門口大媽的身手不再了呀!

小兄弟是個努力的好童鞋. 於是咱自然當仁不讓開始介紹UML, SOA, 4GL, J2EE, Agile Programming, JSR168X --- 噢, 不好意思, 又不小心yy了, 俺是粗淫, 這些說實話不懂地.

咳嗽, 是介紹JUnit, TDD, 和瓜娃 --- 就是Google Collection的重裝上陣: [url=http://code.google.com/p/guava-libraries/]Guava[/url].


[b]一. [url=http://guava-libraries.googlecode.com/svn/trunk/javadoc/com/google/common/collect/Lists.html]Lists[/url]和[url=http://guava-libraries.googlecode.com/svn/trunk/javadoc/com/google/common/collect/Maps.html]Maps[/url][/b]

介紹瓜娃主要是覺得它是個老老實實的能幫助寫代碼的工具庫. 不用把它當作正兒八經的什麼東西學習 (說實話, 那裏面的東西俺估計也就接觸過兩成了不起了), 把那個jar文件放到你的classpath裏, 然後哪怕你就知道一個庫函數呢, 對景的時候也是個幫手啊.

比如, 最簡單地, 用java5以上的話(2010年了, 還在用上古神器jdk1.3或者1.4的首長請舉手. 敬禮! 首長辛苦了!), 你怎麼new一個ArrayList呢? 這樣吧?

[code="java"]List<String> list = new ArrayList<String>();


怎麼new一個HashMap呢? 是不是這樣?
Map<String, Integer> map = new HashMap<String, Integer>();


對俺們這些用慣了瓜娃的懶人, 寫那個<>裏面的東東兩次就覺得累得慌, 除非一些特殊的場合不想依賴瓜娃的jar文件的, 俺們一般都改寫成:

List<String> list = Lists.newArrayList();

Map<String, Integer> list = Maps.newHashMap();


Lists和Maps是兩個工具類, [url=http://guava-libraries.googlecode.com/svn/trunk/javadoc/com/google/common/collect/Lists.html#newArrayList()]Lists.newArrayList()[/url]其實和new ArrayList()幾乎一模一樣, 唯一它幫你做的(其實是javac幫你做的), 就是自動推導(不是"倒")尖括號裏的那坨叉叉.

這兩個東西要說技術含量, 附加價值差不多趨近於0. 但是越是這種簡單的不用腦子的東西, 越是讓人驚訝地有邪異的吸引力. 我就看過好幾個人說, 他們使用瓜娃的主要目的, 就是newArrayList()和newHashMap(). 畢竟, 這東西每個人每時每刻差不多都要用到吧?

當然, 瓜娃提供的遠不止這兩毛五, 買一根小豆冰棍兒都不夠. 比如, 除了new一個空的ArrayList, 你還想往裏放點數據. 直接用jdk的話, 大概是這樣:

List<Integer> list = new ArrayList<Integer>();
list.add(1);
list.add(2);
list.add(3);


用Lists是這樣:
List<Integer> list = Lists.newArrayList(1, 2, 3);


嗯, 是不是有點意思了? 值一個"可愛多"了吧?


[b]二. [url=http://guava-libraries.googlecode.com/svn/trunk/javadoc/com/google/common/collect/ImmutableList.html]ImmutableList[/url]和[url=http://guava-libraries.googlecode.com/svn/trunk/javadoc/com/google/common/collect/ImmutableMap.html]ImmutableMap[/url][/b]

現在主流java社區傾向於同意, immutable對象(就是說狀態不變)是個好東西. 它能讓程序邏輯變得簡單易懂, 而且減少出錯的可能性.

JDK目前不提供immutable集合. 瓜娃提供的最主要的immutable集合, 是ImmutableList, ImmutableSet和ImmutableMap.
顧名思義, 一旦你創建了一個ImmutableList或者ImmutableMap, 你就再也不能改變它了. 它就像你記憶中初戀的那個她, 不管時光荏苒, 滄海桑田, 永遠年輕美麗語笑嫣然 --- 當然, 前提是你還活着.

那麼怎麼創建ImmutableList呢? 嗯, 除非語言直接提供支持, 這應該是最簡單的方式了:
ImmutableList<Integer> list = ImmutableList.of(1, 2, 3);

ImmutableMap一樣簡單:
ImmutableMap<String, Integer> map = ImmutableMap.of(
"1", 1,
"2", 2,
"3", 3
);


對比一下用HashMap的情況:

Map<String, Integer> map = new HashMap<String, Integer>();
map.put("1", 1);
map.put("2", 2);
map.put("3", 3);



還是前者舒服吧?

那麼, 假設你所有的不是事先知道的一些常量. 比如說, 你要從一個數據庫裏讀出一些基本信息保存在內存裏. 用of()就不好使了, 這時候, 可以用builder模式:
ImmutableMap.Builder<String, Integer> builder = ImmutableMap.builder();
for (...) {
builder.put(name, age);
}
ImmutableMap<String, Integer> map = builder.build();


ImmutableList和ImmutableMap最常用的就是創建一些集合常量 (這些常量都是static final的).

另外一個主要的用途, 是作爲其它Immutable對象內部使用的數據結構.


[b]三. 討論[/b]

一個也許會存在爭議, 但是瓜娃開發組強烈推薦的使用方法, 是凡是可能的情況下, 給你的函數的返回類型用ImmutableList和ImmutableMap, 而不是它們實現的接口: List和Map. 比如:

ImmutableList<String> getNames();
ImmutableMap<String, Integer> getAgeMap();

而不是:
List<String> getNames();
Map<String, Integer> getAgeMap();


爲什麼這樣呢? 這是因爲immutable集合是一類特殊集合, 它們不象ArrayList, HashMap那樣是純粹的實現細節, 相反, 這些類型攜帶了重要的語義信息: 它們是不可變的.

如果調用者使用了list.add()或者map.put(), 得到的將是UnsupportedOperationException異常.

通過返回ImmutableMap和ImmutableList, 函數簽名清楚地告訴調用者什麼可以做, 什麼不可以做. 這對大型程序中團隊協作, 代碼理解和維護好處多多.

實際上, 最有爭議的, 是在jdk的集合框架設計上. Sun把List和Map的接口設計爲mutable(可變的), 但是同時允許實現類不實現某些函數, 比如add(), put(). 一些貌似愛思考地程序員(包括俺)就想啦: 爲啥你不乾脆把寫操作分離出來呢? 這樣當一個人拿到ImmutableList的時候, 他根本就沒有add()可以調用, 更甭說運行時拋異常了?

Sun對此專門有個[url=http://download.oracle.com/javase/1.5.0/docs/guide/collections/designfaq.html#1]回答[/url]. 是否信服就由你了. 不過不管喜不喜歡, 我們今天所有的就是這個設計: 一個List可能是可變的也可能是不可變的. 大概還是不要鑽牛角尖, 入鄉隨俗吧.

未完待續
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章