瓜娃之蜻蜓點水 (1) - List和Map



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

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

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

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

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

咳嗽, 是介紹JUnit, TDD, 和瓜娃 --- 就是Google Collection的重裝上陣: Guava.


一. ListsMaps

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

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

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是兩個工具類, Lists.newArrayList()其實和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);


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


二. ImmutableListImmutableMap

如今主流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對象內部使用的數據結構.


三. 討論

一個也許會存在爭議, 可是瓜娃開發組強烈推薦的使用方法, 是凡是可能的狀況下, 給你的函數的返回類型用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對此專門有個 回答. 是否信服就由你了. 不過無論喜不喜歡, 咱們今天全部的就是這個設計: 一個List多是可變的也多是不可變的. 大概仍是不要鑽牛角尖, 入鄉隨俗吧. 未完待續
相關文章
相關標籤/搜索