寫在前面:
之前在一個項目中用到過guava,當時匆匆用,也沒細研究,今天偶然在occhina看到這個系列教程的翻譯,感受不錯,介紹得還比較全面,就一口氣全看完了,但看到第四節,發現還沒翻譯,因而本身就硬着頭皮看了英文,發現也能看懂大概意思,就順手翻譯了一下,也算是爲開源事業作點兒貢獻吧。把文章轉到本身博客記錄一下。
附:
Guava API
Guava 用法整理 html
這個夏天的早些時候,我已經極力向個人全部同事推薦了 Google Collections 。 Kevin Bourrillion說他的一個同事告訴他「沒有使用Google Collections前編程就像把一隻手綁在背後」。
我灰常贊成Kevin的這個同事!
可能文章的標題有點奇怪。我指的是「編寫漂亮代碼」。我猜我應該說「簡潔的」Java代碼,可是,它們意思可不同(譯者注:漂亮的代碼看着很爽,簡潔的不必定爽)。 git
在我準備開始賣力的吆喝這個我最最喜歡的Java類庫前,我有幾個額問題要問問你:
多少次你寫了像下面同樣的代碼: 程序員
Map<String, Map<Long, List<String>>> map = new HashMap<String, Map<Long,List<String>>>();
或者像這樣的不堪入目的代碼: github
int a = 5; int b = 10; int compareTo = Integer.valueOf(a).compareTo(Integer.valueOf(b));
或者有不少的if和else :-(
又有多少次你寫了像下面這樣的代碼,只爲了從一個文件中讀一點點東西?: 數據庫
File file = new File(getClass().getResource("/test.txt").getFile()); BufferedReader reader; String text = ""; try { reader = new BufferedReader(new FileReader(file)); String line = null; while (true) { line = reader.readLine(); if (line == null) { break; } text += line.trim() + "\n"; } reader.close(); reader = null; } catch (FileNotFoundException e1) { e1.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }
好吧,我想說… 這都 TM 什麼玩意?! apache
咱們已經有Apache Commons Collections不少年了。那爲何咱們還須要另一個collections庫呢?我看過不少像這樣的評論: 編程
「任何有一段時間開發經驗的Java程序員都會積累這些類型的實用的工具類」 api
好吧,是的,這對於大多數開發者來講多是(應該是)對的。可是,有太多理由來擺脫垃圾代碼和重用漂亮的工具類!在這個博客裏,我將要告訴你一些的確引發我求知慾-讓我沉溺於其中的事情,那就是Google Collections。 數組
正如Jared Levy 曾說過的:
這個庫簡化了你的代碼,使它易寫、易讀、易於維護。它能提升你的工做效率,讓你從大量重複的底層代碼中脫身。
此外,我會給大家展現一下Guava裏面包含的不少很是酷的功能,讓大家看看如何用它來寫出更漂亮的代碼,一旦看到這些,大家就會和之前那種僵化的使人討厭的寫代碼方式說拜拜了。
Google Guava 是 Google 爲 Java 1.6 編寫的核心庫。它仍然不是一個很成熟的庫,在將來幾個月還將不斷的變化。Google Collections 將在 1.0 版本發佈時將成爲 Guava 的一部分。Guava (和 Google Collections) 已經率先被不少 Google 開發者使用。支持該項目的開發者有 Kevin Bourrillion, Jared Levy, Crazy Bob Lee, Josh Bloch(!) (Google 的 Java 首席架構師) 和 limpbizkit (咱們找不到這傢伙的真實姓名). Google Collections 在 2007 年就已經有了,但 Guava 是在 2009年9月推出的。
做爲這個系列的博客,我將向你介紹 Google Collections 並告訴你使用 Guava 和 Google Collections 能爲你帶來什麼好處。包括代碼量的減小以及新的更快的數據結構。在第二部分咱們將深刻探討 Guava 和 Collections 的一些高級特性。
顯然一篇博文不能深刻地覆蓋Google Collections的方方面面,因此我決定把時間放在我平常編碼中使用到的基礎且不失強大的特性上,首先,不要這麼作:
Map<String, Map<Long, List<String>>> map = new HashMap<String, Map<Long,List<String>>>();
要這麼作:
Map<String, Map<Long, List<String>>> map = Maps.newHashMap();
或者更甚者直接使用靜態導入:
Map<String, Map<Long, List<String>>>map = newHashMap();
很棒,不是嗎?多虧有泛型和寫Collections的哥們提供給咱們的這些方便工廠方法,咱們再也不須要寫一些Java自己應該自帶的東西。好吧,我知道這些會是JDK 7裏的一部分,那固然很好,不過Google Collections如今就有這些功能。
相似於com.google.common.collect.Maps提供的這些靜態工具方法,Lists和Sets也有:
Lists.newArrayList(); Sets.newHashSet();
還有更多! 本身去看看吧![http://code.google.com/p/google-collections/]
當你在寫單元測試時,常常會構造一些測試數據,多是list、map、set等,對於一些像我同樣草率的人來講,測試代碼中會常常看到相似下面的語句:
List<String> list = new ArrayList<String>(); list.add("a"); list.add("b"); list.add("c"); list.add("d");
其實我也知道,這幾行代碼看起來很爛,我只是想用一些測試數據構造一個不可變的list而已,我但願能像下面這樣寫一行代碼搞定這些。。如何辦到?好吧,這很簡單!
ImmutableList<String> of = ImmutableList.of("a", "b", "c", "d");
Map也同樣
ImmutableMap<String,String> map = ImmutableMap.of("key1", "value1", "key2", "value2");
我如今慢慢的愈來愈喜歡這種簡單而又有效的寫代碼的方式,我還想縮短一下上面的代碼,可是因爲ImmutableList和ImmutableMap都有of方法,不能使用靜態導入。不過有一個變通的方法就是說在咱們本身的集合工具中包裝這些建立工廠方法,那麼對於不可變的list和map我只須要簡單的這麼寫就好:
ImmutableMap<String,String> map2 = mapOf("key1", "value1", "key2", "value2")
或者
ImmutableList<String> list2 = listOf("a", "b", "c", "d");
並且若是我想構造填充一個ArrayList(或者一個HashMap),我能夠這樣:
ArrayList<String> list3 = arrayListOf("a", "b", "c", "d");
兩種方式均可以,選擇權在你手上,很明顯,這種較以前面的方式更靈活優雅一些,你說呢? 除去可使用方便乾淨的方式來建立並填充集合類,咱們也提供了不少額外的工具方法,好比過濾,對set取交集和並集,排序等等一些更優雅的方法,我將會在第二部分中講解它們。
在這以前,我想先告訴你我在寫代碼時,是若是借用Eclipse的Code模板功能更高效的使用集合類的。(我假設你瞭解在IDEA或者其餘IDE中也存在相似的功能,你能夠根據這部分敘述作出相應的擴展或變通)
做爲一個Eclipse的用戶,我很是喜歡快捷鍵(參照這篇介紹Eclipse快捷鍵的博文:MouseFeed and how you can easily learn Eclipse shortcuts)
OK,Ctrl+space是大家的好朋友!他也是代碼自動補全的快捷鍵。(譯者注:固然。在中國,因爲這個快捷鍵和切換輸入法衝突,通常都設置爲了「Alt+/」做爲代碼補全的快捷鍵)
在Eclipse下你能夠建立一個模板來綁定到一個自動補全的快捷關鍵字上,這也是魔力所在!
相對於鍵入Maps.newHashMap()來建立一個HashMap,或者乾脆使用靜態導入,就能夠簡單的鍵入newHashMap()來建立一個HashMap,我只是簡單的敲入newH,按下ctrl+space,見證奇蹟的時刻到了!
在Eclipse菜單欄選擇Window -> Preferences,進入Java -> Editor -> Templates,點擊「New」。Name處就是你想敲入的快捷關鍵字,我一般命名爲個人方法名,好比在這裏,就是「newHashMap」,加上你喜歡的描述,好比」Import static Maps.newHashMap「,並增長下面的內容:
${:importStatic(com.google.common.collect.Maps.newHashMap)}newHashMap();${cursor}
以上就是建立快捷補全的所有步驟了,如今去爲你經常使用到的全部方法添加模板吧!
最後,但並不是不重要,我將向你展現一下若是使用Guava來處理本文開頭留下來的兩個問題:
1.從文件中按行讀取內容:
File file = new File(getClass().getResource("/test.txt").getFile()); List<String> lines = null; try { lines = Files.readLines(file, Charsets.UTF_8); } catch (IOException e) { e.printStackTrace(); }
2.比較兩個基本類型:
int compare = Ints.compare(a, b);
3.把一個List轉換爲int數組:
List<Integer> list = listOf(1, 2, 3, 4); int[] array2 = Ints.toArray(list);
Guava爲咱們提供了對Core Java類庫全面的擴展,咱們可使用com.google.common.primitices包下的Ints,Doubles,Floats,Shorts,Bytes以及Bools等工具類操做基本類型的數據;com.google.common.io包提供了操做streams,buffers以及files等等,並且併發包中提供了一些像Futures,Callables以及Executors等方便的工具類來減輕咱們寫併發代碼的痛苦。除此以外,Guava提供了對Collections的加強,以及很是優雅的CharMatcher、Joiner以及Splitter類,這些類我將在下篇博文中提到。
能夠從這裏得到源碼:
svn checkout http://guava-libraries.googlecode.com/svn/trunk/guava-libraries-read-only
下次咱們會深刻Guava 的高級功能,探索一下集合的用法,看看怎樣經過Multimap使java的功能更增強大,如何用mapping功能來轉換集合。請拭目以待。若是大家也用過Guava或者Google Collections請分享一下大家的心得。
在這個系列的第一部分裏,我簡單的介紹了很是優秀的Google collections和Guava類庫,並簡要的解釋了做爲Java程序員,若是使用Guava庫來減小項目中大量的樣板代碼。在這篇博文中咱們將深刻挖掘Guava提供的更高級的特性。 咱們將深刻挖掘Guava庫,並瞭解一下優雅的CharMatcher類、Joiner以及Splitter類,以及在處理Java基本類型時Guava給咱們帶來的別的工具類。
CharMatcher 能夠很是方便地添加到你的java工具箱中。有些人形容它:「像打了興奮劑的StringUtils」:p 你可使用預先設定好的常量,好比CharMatcher.WHITESPACE, CharMatcher.JAVA_DIGIT 或者CharMatcher.ASCII,此外你還有不少簡便的工廠方法如CharMatcher.is(‘aaa’), CharMatcher.isNot(‘bbb’), CharMatcher.oneOf(‘abcd’).negate(),甚至更復雜一些好比:
CharMatcher.inRange('a', 'z').or(inRange('A', 'Z'));
固然你能夠繼承它而後實現方法 matches(char c)。你能夠把 Google Collection中都創造實現一遍(固然下次咱們會覆蓋到)!
若是你想從字符串中獲得全部的數字,那麼你能夠這樣:
String string = CharMatcher.DIGIT.retainFrom("some text 89983 and more");
若是你想把字符串中的數據都去掉,能夠以下:
String string = CharMatcher.DIGIT.removeFrom("some text 89983 and more");
還有好多匹配的方法:
matchesAllOf(CharSequence)
atchesAnyOf(CharSequence)
matchesNoneOf(CharSequence)
除了indexIn, lastIndexIn and countIn這些方法,還有不少trimming, replacing and collapsing相關的方法。 更多信息查看Java doc.
目前Joiner仍是Collections 的一部分,Splitter 已經加入了Guava (不過一旦Collections 發佈1.0版本,那麼它們會一塊兒加入到Guava)。
能夠這麼使用Joiner:
String[] subdirs = { "usr", "local", "lib" }; String directory = Joiner.on("/").join(subdirs);
或者這樣:
int[] numbers = { 1, 2, 3, 4, 5 }; String numbersAsString = Joiner.on(";").join(Ints.asList(numbers));
得益於Guava對基本型的支持,能夠很方便這麼處理:
String numbersAsStringDirectly = Ints.join(";", numbers);
對於字符串,咱們能夠直接進行分割,可是這樣作多少有些奇怪, Splitter 提供了更多的操做,並且更加健壯。字符創分割一般返回的是一個數組而 Splitter 返回的是一個迭代 Iterable。
Iterable split = Splitter.on(",").split(numbsAsString);
你能夠簡單地分割字符串:
String[] splitRegular = testString.split(",");
可是當須要處理下面這樣的字符串時:
String testString = "foo , what,,,more,";
輸出結果是:
‘foo ‘
‘ what’
」
」
‘more
這樣的結果也許還能夠,可是Splitter容許咱們對分割結果作更多的控制:
Iterable<String> split = Splitter.on(",").omitEmptyStrings().trimResults().split(testString);
獲得的結果是 foo’,'what’,'more’
Joiner和Splitter都是可配置的,甚至你能夠把Joiner使用在map中。
最後再看個幾個例子加深印象吧:
String str = "test1, , test2, test3"; Iterable<String> strArr = Splitter.on(',') .trimResults() .omitEmptyStrings() .split(str); Output:-> ["test1", "test2", "test3"]
String str = "key1: 1; key2: 2 ; key3: 3"; Map<String, String> m = Splitter.on(';') .trimResults() .withKeyValueSeparator(":") .split(str); Output:-> {key1= 1, key2= 2, key3= 3} private static final Splitter COMMA_SPLITTER = Splitter.on(',') .trimResults() .omitEmptyStrings(); COMMA_SPLITTER.split("foo, ,bar, quux,"); Output:-> ["foo", "bar", "quux"]
ArrayList<String> strArr1 = Lists.newArrayList( "test1","test2","test3",null,"test4",null,null); Joiner.on(';') .skipNulls() .join(strArr1); Output:-> "test1;test2;test3;test4" Joiner.on(';') .useForNull("_") .join(strArr1); Output:-> "test1;test2;test3;_;test4;_;_"
Map<String, String> map = Maps.newHashMap(); map.put("key1", "value1"); map.put("key2", "value2"); map.put("key3", null); map.put("key4", "value3"); Joiner.on(';') .useForNull("NULL") .withKeyValueSeparator("=") .join(map); Output:-> "key4=value3;key3=NULL;key2=value2;key1=value1"
ArrayList<String> strArr = Lists.newArrayList( " test1","test2 "," test3 ",null,"test4",null,null,"", " "); Predicate<String> EMPTY_OR_NULL_FILTER = new Predicate<String>() { @Override public boolean apply(String str){ str = Strings.nullToEmpty(str).trim(); return !Strings.isNullOrEmpty(str); } }; Function<String, String> TRIM_RESULT = new Function<String, String>(){ @Override public String apply(String str){ return Strings.nullToEmpty(str).trim(); } }; String joinStr = Joiner.on(';') .skipNulls() .join(Collections2.transform(Collections2.filter(strArr, EMPTY_OR_NULL_FILTER), TRIM_RESULT)); Output:-> "test1;test2;test3;test4"
public static void main(String[] args) { String tmpValue = "a_b_c_1_2_3"; String[] valArr = tmpValue.split("_"); // 求字符串數組的子串,並最後拼接起來 String tmpVal = ""; for (int i = 1; i < valArr.length; i++) { tmpVal = tmpVal.equalsIgnoreCase("") ? valArr[i] : tmpVal + "_" + valArr[i]; } System.out.println(tmpVal); System.out.println("———————"); // 上面這麼一段與下面這句等價 System.out.println(Joiner.on("_").join(Lists.newArrayList(valArr).subList(1, valArr.length))); } // 結果: b_c_1_2_3 ——————— b_c_1_2_3
在博客的第一部分,我簡單提到了基本型的用法。Guava已經提供了諸如Ints.compare(a, b)和Ints.toArray(list)。
讓我介紹Guava 關於基本型提供的更多的一些用法吧。
假如我有一個整型數字數組,咱們想知道數組中是否有特定的整型數字。傳統的寫法以下:
int[] array = { 1, 2, 3, 4, 5 }; int a = 4; boolean hasA = false; for (int i : array) { if (i == a) { hasA = true; } }
使用Guava,咱們能夠以下:
boolean contains = Ints.contains(array, a);
一樣,其餘類型的基本型數組也能夠這麼來作。咱們甚至能夠直接對數組作以下的事:
int indexOf = Ints.indexOf(array, a); int max = Ints.max(array); int min = Ints.min(array); int[] concat = Ints.concat(array, array2);
在這個系列的下一章咱們將關注下 Google Collections library包的更高級特性如:Functions, Filtering and Ordering!歡迎繼續收看,請與咱們分享你的見解。
在本系列博客的第1、二部分,我介紹了很是優秀的Google Collections和Guava包。本篇博客中咱們來看看如何使用Google Collections來作到過濾和排序功能。此外,我會帶你看看Google Collections是如何使Java有一點點「functional(方法化)」的進步了。
Google Collections給咱們帶來了一對很是優雅的東東,叫作:Functions and Predicates! 和你使用的scala同樣有神奇的地方,如今你可使用在no-functional 的java身上了。你能夠在com.google.common.base包裏找到這些(更多)。
咱們將在下一部分過濾集合的時候談到Predicates類,首先咱們先看一下Function的用法!
Google collections提供了Function接口,實際上,一個function就是從一個對象到另一個對象的轉換變形。
像Lists和Maps這類的Collection工具類給咱們提供了轉換的方法:
topMap = Maps.transformValues(fromMap, function); toList = Lists.transform(fromList, function);
舉個例子來講,假設你有一個Map,key是物品,value是對應的價格,單位是歐元。那麼,你有個需求是將裏面的價格都轉換爲美圓,傳統的作法是遍歷整個Map,而後更新每一個value值,將價格轉換爲美圓價格,好麻煩...
有了Functions,世界一會兒變清淨了...
Map usdPriceMap = Maps.transformValues(eurPriceMap, new Function() { double eurToUsd = 1.4888; public Double apply(final Double from) { return from * eurToUsd; } });
好吧,你可能說匿名內部類搞的有點糟,由於 你可能想重用這個function---這裏只是演示函數式的一些特色而已。
和這個相似的,咱們也可使用Functions來把一個對象轉換成一個徹底不一樣的對象,好比將一個整形轉換爲字符串。
咱們稍後再深刻Functions類,首先咱們瀏覽一下Multimap集合以及咱們若是使用一點function來轉換一個集合。
我在Integrasco作數據工做時遇到的最多見的任務是過濾數據和對大集合進行排序。 簡單起見,咱們假設你有一個姓名列表想要過濾(看起來有點幼稚):
List<String> names = listOf("Aleksander", "Jaran", "Integrasco", "Guava", "Java");
咱們可使用com.google.common.collect.Iterables和com.google.common.base.Predicates類來過濾例子中的列表,使過濾後的列表中只包含Aleksander或者Jaran:
如今我知道這聽起來有點傻帽,可是你仍然能夠實現本身的Predicates條件類,好比返回名字長度小於5的列表(我從codemonkeyism.com偷到了下面這個例子):
Iterable<String> filtered = filter(names, or(or(equalTo("Aleksander"),equalTo("Jaran")), lengthLessThan(5)));
這個例子返回的是Aleksander,Jaran以及Java(由於Java的長度小於5)。or條件的部分讀起來有點繞,但我還能夠忍受。equalTo以及or條件都是Predicates自帶的方法,用起來很方便。
如今咱們來實現一個lengthLessThan的條件,咱們只須要這麼作:
private static class LengthLessThanPredicate implements Predicate<String> { private final int length; private LengthLessThanPredicate(final int length) { this.length = length; } public boolean apply(final String s) { return s.length() < length; } }
把這個實如今你的工具類裏包裝一下就像這樣:
public static Predicate<String> lengthLessThan(final int length) { return new LengthLessThanPredicate(length); }
關注一下Stephan的博文fluent interfaces for Google Collections --寫的至關優雅~!
多虧有了java Collections類,咱們能夠這麼排序:
Collections.sort(List<T>, Comparator<? super T>)
但有時候咱們想作更復雜一些的事情,好比合並多個Comparator或者咱們可能只是想要排序過的集合的一個視圖,而不改變原來集合的順序。
Google Collections給咱們提供了Ordering,讓咱們更好地掌控排序。假如咱們有兩個對Person類排序的comparator,一個是根據lastName排序,一個是根據firstName排序:
Comparator<Person> byLastName = new Comparator<Person>() { public int compare(final Person p1, final Person p2) { return p1.getLastName().compareTo(p2.getLastName()); } } Comparator<Person> byFirstName = new Comparator<Person>() { public int compare(final Person p1, final Person p2) { return p1.getFirstName().compareTo(p2.getFirstName()); } };
那麼,假如咱們如今想現根據last name排序,再根據first name排序,而後對排序結果反序,那咱們咱們須要作的是:
List<Person> sortedCopy = Ordering.from(byLastName).compound(byFirstName).reverse().sortedCopy(persons);
並且,你甚至無需建立Comparator比較器,你能夠直接擴展Ordering類!
List<Person> sortedCopy = orderByLastName.compound(orderByFirstName).reverse().sortedCopy(persons);
在這個系列的第一部分,Steve提到了在Scala中,你能夠這麼作:
people.filter(_.firstName == "Steve").sort(_.lastName < _.lastName)
功能是說從people這個集合中篩選出firstName爲「Steve」的,而且按他們的lastName屬性排序。
從語法上來看,這行代碼很是優雅!那麼咱們也來看一下使用Google Collections時應該怎麼作。Google Collections給咱們提供了前面提到的Iterables類,咱們可使用Iterables類來實現過濾和轉換(你可使用Google Collections裏的Collections2來實現一樣的功能)。
那如今咱們就來看一下如何實現和Steve的那行Scala代碼同樣的功能,雖然看起來沒有Scala實現的那麼優雅,但倒是使用Predicates和Ordering類來實現上面功能的一種方式。
Ordering.from(byLastName).sortedCopy(filter(persons, withFirstName("Steve")));
雖然跟Scala提供的語法糖有點差距(很明顯咱們仍是須要咱們的「withFirstName」條件謂詞以及「byLastName」比較器),但至少這比咱們不使用Google Collections接近多了!(若是採用Stephen的流式接口的話,代碼會更易讀)。
Kevin Bourrillion在另外一篇關於使用Google Collections編寫函數式的Java的文章中提到:
語法很爛。並且同時這在語言自己改變以前只是權宜之計,到那時咱們才真正的選擇最佳的語法並開始真正的函數式編程。因此我還沒決定我會投入多大的努力到Function/Predicate中去(這段真的很難翻譯..我去..)
在下篇也是最後一篇關於Google Collections和Guava的博文中,咱們將看到若是使用Google Collections操做Set和Map,以及使用Preconditiones來作驗證,並且咱們帶你體驗一下奇妙的Multimap集合類以及如何進行切分!拭目以待吧!
在本系列博客的前三章,咱們大概介紹了Google的Guava類庫和Collections類庫,做爲一名Java開發人員,相信你會從使用這些類庫,進而來減小在你項目中使用樣板文件的數量而獲益。在本系列博客的最後一篇中,我將帶你們來了解一個會讓你徹底愛上並沉浸於其中的的集合工具類-Multimap。咱們將帶你們瞭解下如何使用Google Collections的Preconditions來作校驗,可是在此以前,先讓咱們來了解下如何對Set和Map進行交集、並集和差集的運算。
有時,當咱們須要去對兩個Set的取交集、並集和差集的時候,那是一件相關麻煩的事情,並且代碼看起來很凌亂。常常狀況,你會以一遍又一遍的循環來結束這種作法。可是若是咱們使用Google Collections提供的Sets類就能夠垂手可得的完成這些操做,而且是徹底免費的!
HashSet setA = newHashSet(1, 2, 3, 4, 5); HashSet setB = newHashSet(4, 5, 6, 7, 8); SetView union = Sets.union(setA, setB); System.out.println("union:"); for (Integer integer : union) System.out.println(integer); SetView difference = Sets.difference(setA, setB); System.out.println("difference:"); for (Integer integer : difference) System.out.println(integer); SetView intersection = Sets.intersection(setA, setB); System.out.println("intersection:"); for (Integer integer : intersection) System.out.println(integer);
From the Public Object blog:
「不一樣於慣例,這些方法沒有作任何的拷貝。相反,他們返回了表明了這兩個集合的視圖。 可是在有些狀況下,這些拷貝又頗有用,咱們能夠用immutableCopy類中提供的一個便利方法來實現拷貝」
一樣地,對於Map而言,咱們能夠像下面這樣處理:
MapDifference differenceMap = Maps.difference(mapA, mapB);
若是用MapDifference類,咱們還能夠這樣:
differenceMap.areEqual(); Map entriesDiffering = differenceMap.entriesDiffering(); Map entriesOnlyOnLeft = differenceMap.entriesOnlyOnLeft(); Map entriesOnlyOnRight = differenceMap.entriesOnlyOnRight(); Map entriesInCommon = differenceMap.entriesInCommon();
Thank you, Google Collections!
早在初夏的時候,一個叫剛剛加入咱們的同事Bent André向我介紹了用Preconditions進行校驗的想法,可是,直到最近我才發現Google Collections實際上已經包含了相應的實現(咱們本身也已經有了類似的實現)。
那麼這個實現具體是什麼樣子的呢?校驗就是要求咱們準確無誤的作一些事情,一般狀況下,它看起來就是相似下面這樣的代碼:
if (count <= 0) { throw new IllegalArgumentException("must be positive: " + count); }
咱們想校驗調用咱們的方法的方法傳參是否正確,若是錯了,應該發出一個「他出錯了」的警告信息。 JavaDoc中是這樣解釋的:
「Precondition異常一般表示被調用方法發生了一個錯誤。它告訴調用者不能用這種方式、這種參數或者其它來調用這個方法。Postcondition或其它運行失敗是不會拋出這種類型的異常的。」
所以用Preconditions類或者靜態導入,咱們就能夠用下面這行簡單的代碼來替代上面那些的冗長的代碼了:
checkArgument(count > 0, "must be positive: %s", count);
一樣,該類裏還有其它相似的方法來檢驗狀態和空值。
checkNotNull(entry);
至關簡潔,不是麼?
「請注意這裏是相反的表達(譯者注:應該指的是checkNotNull中有not的意思,因此是相反的); 你用Preconditions聲明什麼是你指望返回true的,就好像你在Java中運用斷言,或者在JUnit中調用assertTrue方法同樣。」
From the excellent blog series on Google Collections over at Public Object:
「Preconditions提供對方法狀態的校驗。它能使你輸入的參數如你所指望的的那樣足夠簡潔,與Java內建的斷言不一樣的是Preconditions是一直開啓的。」
下面是我在Integrasco上翻遍我全部的代碼中,找到的一個比較好的例子:
public PostExample(final String title, final Date date, final String author) { //some code to validate that title is not null //some code to validate that date is not null //some code to validate that author is not null this.title = title; this.date = date; this.author = author; }
用了Preconditions以後咱們再來看看代碼變得有多工整:
public PostExample(final String title, final Date date, final String author) { this.title = checkNotNull(title); this.date = checkNotNull(date); this.author = checkNotNull(author); }
很簡潔,不是麼?
稍後咱們會發表一篇關於異常和校驗的更詳細的文章,敬請關注!
我已經數不清我有多少次須要在一個Map中實現一個key對應多個value的需求,最終不得不以Map<K, List<V>>這種結構來實現的經歷了。 而且用這種方式實現一鍵多值的需求還存在很大的爭議,以下所示:
Map<Person, List<BlogPost>> map = new HashMap<Person, List<BlogPost>>(); public void addBlogPost(final Person author, final BlogPost blogPost) { List<BlogPost> blogPosts = map.get(author); if (blogPosts == null) { blogPosts = new ArrayList<BlogPost>(); map.put(author, blogPosts); } blogPosts.add(blogPost); }
別告訴你你歷來沒這樣作過?利用Google Collections中的Multimap類咱們能夠輕鬆實現上述需求,並且感受很時髦(我很開心我能夠這樣表達):
Multimap<Person, BlogPost> multimap = ArrayListMultimap.create(); public void addBlogPost(final Person author, final BlogPost blogPost) { multimap.put(author, blogPost) }
Whoop, whoop!
Google Collections提供了多種Multimaps的實現,若是你想防止出現鍵值對,能夠用HashMultimap;若是你須要鍵值對按照天然順序排列,你可使用TreeMultimap;甚至你想按插入順序來遍歷集合,LinkedHashMultimap能夠知足你的需求。
Multimaps一樣提供了不少有用的方法,詳細內容能夠參考Multimap 和 Multimaps的API文檔!很激動是麼?那就繼續往下看吧...
我管這節叫分片,相信不少人會以爲叫咱們在以前文章叫提到的「過濾集合」更準確。可是當咱們把把Multimap的概念和功能相結合的時候,你就會意識到他到底有多強大了,而不只僅是過濾那麼簡單!
咱們假設咱們已經擁有了包含了一組map的list。list裏的每個Map表明擁有指定屬性的一個文檔。這個Map看起來可能會是下面這個樣子:
mapOf("type", "blog", "id", "292", "author", "john");
即每一個Map中咱們擁有3個屬性,他們分別是「type」、 「id」和「author」。
如上所示,全部咱們的List看起來應該是下面這個樣子:
List<Map<String, String>> listOfMaps
如今,咱們想把這個list根據所裝載對象的類型不一樣分紅多個list,好比一個叫「blog」,一個叫「news」等等...
若是沒有Google Collections這將是一場惡夢!咱們必須得先循環這個list,而後再分別檢查每個map中的key,而後再把根據類型的不一樣放入不一樣的list中。但若是咱們不知道map裏都有哪些類型,這個過程會更痛苦!
想不想和我一塊兒來看看有沒有輕鬆的辦法解決?
用一點點Function的魔法加上Multimaps,我樣能夠以一種上至關優雅的方式來解決這個問題:
Multimap<String, Map<String, String>> partitionedMap = Multimaps.index(listOfMaps, new Function<Map<String, String>, String>() { public String apply(final Map<String, String> from) { return from.get("type"); } });
如今咱們擁有了每個key表明不一樣類型的Multimaps了!
若是如今咱們想要指定類型的全部map,惟一須要作的就是找Multimaps要!
好,就到這裏爲止了!但願你喜歡這段旅程,同時也但願你能從Google這些真正偉大的項目中受到啓發!
歡迎反饋!
https://github.com/ecchanger/myblog/tree/master/posts
http://macrochen.iteye.com/blog/737058
http://www.oschina.net/search?scope=translate&q=Google+Collections
http://www.ibm.com/developerworks/cn/java/j-lo-googlecollection/
http://docs.guava-libraries.googlecode.com/git-history/release/javadoc/index.html
http://techneerajnandwana.blogspot.com/2011/11/guava-string-manipulation-with.html
http://commons.apache.org/proper/commons-lang/javadocs/api-release/index.html
簡介:該工具類集合是由 apache 負責維護的,裏面對多種常見的 java 操做作了封裝,如 讀寫文件、發 email、jdbc 訪問數據庫、文件上傳、圖像處理、字符串/集合/xml 的處理等,讓你告別繁瑣的 java 操做~
google Guava包的ListenableFuture解析
http://ifeve.com/google-guava-listenablefuture/
http://ifeve.com/google-guava/