Google Guava 筆記

一、引言

    Guava 是 google 幾個java核心類庫的集合,包括集合 [collections] 、緩存 [caching] 、原生類型支持 [primitives support] 、併發庫 [concurrency libraries] 、通用註解 [common annotations] 、字符串處理 [string processing] 、I/O等等。

    我們平時經常遇到某些相同的問題自己寫代碼也都能解決。但是久而久之會感覺到很痛苦因爲我們一直在做着重複的工作。爲了不再忍受痛苦也許我們可以總結自己的類庫但是自己總結的類庫很難與大家分享不能幫助到更多人。同時自己的類庫要不斷的進行維護。而 guava 正是出於這樣的目的誕生的。


二、優勢在哪裏

    光說不練假把式接下來就舉兩個例子給大家感受下。

1.判斷不爲NULL且不爲空

String str=...;  
//use java  
if(str !=null && !str.isEmpty()){  
    //do something  
}  
  
  
//use guava  
if(!Strings.isNullOrEmpty(str)){  
    //do something  
}

2.複製文件

File from=...;  
File to=...;  
  
//use java  
FileInputStream in=new FileInputStream(from);  
FileOutputStream out=new FileOutputStream(to);  
byte[] buff=new byte[1024];  
int readLength=-1;  
while((readLength = in.read(buff)) > 0){  
    out.write(buff, 0, readLength);  
}  
in.close();  
out.close();  
  
//use guava  
Files.copy(from,to); //注意只用了一行代碼噢

    對比下稍微能感受到些它的優勢了吧……接下來介紹下它的一些常用方法和新類型集合。


三、字符串相關工具類

//判斷是否爲空或null
Strings.isNullOrEmpty(null);//returns true
//將空字符串轉換爲null
Strings.emptyToNull("");
//將null轉換爲空字符串
Strings.nullToEmpty(null);
//Joiner
Joiner.on("-").join("2014", "09", "18");//2014-09-18
//splitter
Splitter.on(',').trimResults().split("a , b")
Splitter.on(',').omitEmptyStrings().split("a,,b");
//大寫轉換
CaseFormat.LOWER_CAMEL.to(CaseFormat.UPPER_UNDERSCORE, "helloGuava");
//toString
Objects.toStringHelper(this).add("x", 1).toString();//ClassName{x=1}
Objects.toStringHelper("MyObject").add("x", 1).toString();//MyObject{x=1}
//基本類型的比較
int compare = Ints.compare(a, b);
//獲取字符串中的數字
CharMatcher.DIGIT.retainFrom("some text 89983 and more");
//去除字符串中的數字
CharMatcher.DIGIT.removeFrom("some text 89983 and more");
//Ints中一些用法
int[] array = { 1, 2, 3, 4, 5 };  
int a = 4;  
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);


四、IO類

1.ByteStreams提供了針對字節流的工具方法

InputStream from=...;  
OutputStream to=...;  
ByteStreams.copy(from,to); //複製

2.CharStreams提供了針對字符流的工具方法

Reader from =...;  
Writer to =...;  
CharStreams.copy(from, to); //複製

3.Files提供了針對文件的工具方法

File from=...;  
File to=...;  
Files.copy(from, to); //複製


Files.deleteDirectoryContents(File directory); //刪除文件夾下的內容(包括文件與子文件夾)  
Files.deleteRecursively(File file); //刪除文件或者文件夾  
Files.move(File from, File to); //移動文件

4.Resources提供了針對classpath下資源操作的工具方法

URL url = Resources.getResource("config.xml"); //獲取classpath根下的config.xml文件url

    恩開胃小菜已經完畢接下來要介紹的纔是這篇文章的主食guava集合類。

五、Google Guava Collections

    Google Guava Collections其實就是Java Collections Framework 的增強和擴展。在有些場合你使用了 Java Collections Framework 的 API但還是需要寫很多代碼來實現一些複雜邏輯這個時候就可以嘗試使用 Guava Collections 來幫助你完成這些工作。這些高質量的 API 使你的代碼更短更易於閱讀和修改工作更加輕鬆。

    先看個比較直觀的表格對二者進行對比下

集合接口屬於JDK還是Guava對應的Guava工具類
CollectionJDKCollections2不要和java.util.Collections混淆
ListJDKLists
SetJDKSets
SortedSetJDKSets
MapJDKMaps
SortedMapJDKMaps
QueueJDKQueues
MultisetGuavaMultisets
MultimapGuavaMultimaps
BiMapGuavaMaps
TableGuavaTables


  1. 集合的創建靜態工廠方式

JDK1.7之前我們初始化一個集合嚴謹的話要寫泛型特別不爽

List<TypeThatsTooLongForItsOwnGood> list = new ArrayList<TypeThatsTooLongForItsOwnGood>();

而guava的寫法就相對方便很多

List<TypeThatsTooLongForItsOwnGood> list = Lists.newArrayList();
Map<KeyType, LongishValueType> map = Maps.newLinkedHashMap();

但JDK1.7後的已經改進了寫法

List<TypeThatsTooLongForItsOwnGood> list = new ArrayList<>();

既然JDK1.7已經改進了那爲何還要用guava呢其實guava主要還是針對JDK1.5後的擴展經歷了那麼就的時間它的優勢當然有所弱化。但是你要知道的是它的強悍之處遠不僅於此……

例如集合的快速初始化

List<String> theseElements = Lists.newArrayList("alpha", "beta", "gamma");

初始化指定大小提高了性能和可讀性

List<Type> exactly100 = Lists.newArrayListWithCapacity(100);
List<Type> approx100 = Lists.newArrayListWithExpectedSize(100);    
Set<Type> approx100Set = Sets.newHashSetWithExpectedSize(100);


2.不可變集合 Immutable Collections

    顧名思義即爲不可修改的集合。那爲什麼要用不可變集合它的好處和用法呢

    這些不是一兩句話能說清的所以強烈推薦《Immutable Collections[Google Guava] 2.1-不可變集合》這篇文章裏頭說得非常清楚我也就省點口水不囉嗦。用法呢大致分爲這三種

(1).copyOf方法如ImmutableSet.copyOf(set);
(2).of方法如ImmutableSet.of(“a”, “b”, “c”)或 ImmutableMap.of(“a”, 1, “b”, 2);
(3).Builder工具如

public static final ImmutableSet<Color> GOOGLE_COLORS =
        ImmutableSet.<Color>builder()
                .addAll(WEBSAFE_COLORS)
                .add(new Color(0, 191, 255))
                .build();


3.常用集合方法

    set集合

SetView<Integer> union = Sets.union(setA, setB);
System.out.println("union:");
//合併
for (Integer integer : union)
    System.out.println(integer);

SetView<Integer> difference = Sets.difference(setA, setB);
System.out.println("difference:");
//差集
for (Integer integer : difference)
    System.out.println(integer);

SetView<Integer> intersection = Sets.intersection(setA, setB);
System.out.println("intersection:");
//交集
for (Integer integer : intersection)
    System.out.println(integer);
 
Set<String> animals = ImmutableSet.of("gerbil", "hamster");
Set<String> fruits = ImmutableSet.of("apple", "orange", "banana"); 
//返回所有集合的笛卡兒積
Set<List<String>> product = Sets.cartesianProduct(animals, fruits);
// {{"gerbil", "apple"}, {"gerbil", "orange"}, {"gerbil", "banana"},
//  {"hamster", "apple"}, {"hamster", "orange"}, {"hamster", "banana"}}
//返回給定集合的所有子集 
Set<Set<String>> animalSets = Sets.powerSet(animals);
// {{}, {"gerbil"}, {"hamster"}, {"gerbil", "hamster"}}

    Map集合

Map<String, Integer> left = ImmutableMap.of("a", 7, "b", 2, "w", 1);
Map<String, Integer> right = ImmutableMap.of("a", 1, "d", 2, "c", 3);
//比較兩個Map以獲取所有不同點
MapDifference<String, Integer> diff = Maps.difference(left, right);
//返回值爲true則連個map集合相同
diff.areEqual();//false
//鍵相同但是值不同值映射項  
diff.entriesDiffering();//{a=(7, 1)}
//兩個Map中都有的映射項包括匹配的鍵與值
diff.entriesInCommon(); // {}
//鍵只存在於左邊Map的映射項
diff.entriesOnlyOnLeft(); // {w=1, b=2}
//鍵只存在於右邊Map的映射項
diff.entriesOnlyOnRight(); // {d=2, c=3}

    List集合

List<Integer> countUp = Ints.asList(1, 2, 3, 4, 5);
List<Integer> countDown = Lists.reverse(countUp); // {5, 4, 3, 2, 1}
List<List<Integer>> parts = Lists.partition(countUp, 2);//{{1,2}, {3,4}, {5}}

    MultimapinvertFrom、forMap

Map<String, Integer> map = ImmutableMap.of("a", 1, "b", 1, "c", 2);

//多對一的Map反轉爲一對多的Multimap
SetMultimap<String, Integer> multimap = Multimaps.forMap(map);
// multimap["a" => {1}, "b" => {1}, "c" => {2}]

//把一對多的Multimap反轉多對一的Multimap
Multimap<Integer, String> inverse = Multimaps.invertFrom(multimap, HashMultimap<Integer, String>.create());
// inverse[1 => {"a","b"}, 2 => {"c"}]


4.一些亮點用法

以前你是這麼寫

public Directions(Address from, Address to, List<Step> steps) {  
  this.from = from;  
  this.to = to;  
  this.steps = Collections.unmodifiableList(new ArrayList<Step>(steps));  
}

現在你可以這麼寫參數集合不可變

public Directions(Address from, Address to, List<Step> steps) {  
  this.from = from;  
  this.to = to;  
  this.steps = ImmutableList.of(steps);  
}


曾經合併兩個集合再遍歷

public boolean orderContains(Product product) {  
  List<LineItem> allLineItems = new ArrayList<LineItem>();  
  allLineItems.addAll(getPurchasedItems());  
  allLineItems.addAll(getFreeItems());  
  
  for (LineItem lineItem : allLineItems) {  
    if (lineItem.getProduct() == product) {  
      return true;  
    }  
  }  
  return false;  
}

現在你可以不用不用再多去創建一個大集合不妨這麼寫

public boolean orderContains(Product product) {  
  for (LineItem lineItem : Iterables.concat(getPurchasedItems(), getFreeItems())) {  
    if (lineItem.getProduct() == product) {  
      return true;  
    }  
  }  
  return false;  
}


以前想寫個雙向map簡直是累死人了

private static final Map<Integer, String> NUMBER_TO_NAME;  
private static final Map<String, Integer> NAME_TO_NUMBER;  
  
static {  
  NUMBER_TO_NAME = Maps.newHashMap();  
  NUMBER_TO_NAME.put(1, "Hydrogen");  
  NUMBER_TO_NAME.put(2, "Helium");  
  NUMBER_TO_NAME.put(3, "Lithium");  
    
  /* reverse the map programatically so the actual mapping is not repeated */  
  NAME_TO_NUMBER = Maps.newHashMap();  
  for (Integer number : NUMBER_TO_NAME.keySet()) {  
    NAME_TO_NUMBER.put(NUMBER_TO_NAME.get(number), number);  
  }  
}  
  
public static int getElementNumber(String elementName) {  
  return NUMBER_TO_NAME.get(elementName);  
}  
  
public static string getElementName(int elementNumber) {  
  return NAME_TO_NUMBER.get(elementNumber);  
}

但現在你只要寫簡單的兩三行就可以

private static final BiMap<Integer,String> NUMBER_TO_NAME_BIMAP  
  = new ImmutableBiMapBuilder<Integer,String>()  
      .put(1, "Hydrogen")  
      .put(2, "Helium")  
      .put(3, "Lithium")  
      .getBiMap();


六、參考資料

  1. 併發編程網《Google Guava官方教程中文版》

  2. 在線API文檔Guava api文檔

  3. 瘋狂的菠菜博客http://macrochen.iteye.com/blog/737058


七、結語

    Guava的內容並不少本文只是簡單粗略的介紹了些基本信息。借鑑了許多網絡的事例個人覺得想要掌握還是得去多用同時結合者api文檔。堅持是一種精神分享是一種快樂


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