1. 程式人生 > >Google Guava學習筆記

Google Guava學習筆記

Java Collection Framework的增強工具類Google Guava Collection 使用這個工具包的主要原因是為了當使用collection等類處理複雜邏輯的時候,可以使用Guava collection幫助完成這些工作。使得程式碼等短,程式碼質量更高,同時更容易閱讀和修改。 功能舉例: Multiset: 能夠把重複的元素放入一個集合,並且可以統計元素數量 Multimap:能夠實現同一個key對應多個元素,不用自己繁瑣地實現 BiMap:key不重複,value也不重複 Ordering: 作為比較器進行排序,簡化程式碼 如果你對上述功能有興趣,那請你繼續閱讀。

函數語言程式設計:Function和Predicate

Function類:通過Function類將指定的集合類轉變為我們想要的集合類 Predicate類:通過Predicate類將制定的集合類進行過濾,從而剔除集合中不想要的元素

首先我們構建一個Company類

package rich.model;

import java.util.Arrays;
import java.util.List;

import com.google.common.collect.Lists;

public class Company {

 private List<Company> companies;
 private String name;
 private String location;

 public static Company newCompany(String name, String loc) {
  Company company = new Company();
  company.setName(name);
  company.setLocation(loc);
  return company;
 }
 
 public void init() {
  companies = Lists.newArrayList();
  companies.addAll(Arrays.asList(Company.newCompany("quest", "zhuhai"),Company.newCompany("dell", "toronto")));
 }
 public String getName() {
  return name;
 }

 public void setName(String name) {
  this.name = name;
 }

 public String getLocation() {
  return location;
 }

 public void setLocation(String location) {
  this.location = location;
 }
 
 public List<Company> getCompanies() {
  return companies;
 }

 public void setCompanies(List<Company> companies) {
  this.companies = companies;
 }
 }
其次我們構建一個FunctionTest,用於測試Function類的功能:
package rich.base;

import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import rich.model.Company;

import com.google.common.base.Function;
import com.google.common.collect.Collections2;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.base.Functions;

public class FunctionTest {

 public static void main(String[] args) {
  //介面Function<F,T> {T apply(F input) }
  //把一種形式的Collection<F>轉換成另一種Collection<T>
  Function<Company, String> function1 = new Function<Company, String>() {
   @Override
   public String apply(Company company) {
             return company.getLocation();
         }
  };
  //進行轉換
  Company company = new Company();
  company.init();
  List<String> companyLocationList = Lists.transform(company.getCompanies(), function1);
  //Collection<String> collectionCompanyList = Collections2.transform(company.getCompanies(), function1);
  for(int i = 0; i < companyLocationList.size(); i++) {
   System.out.println(companyLocationList.get(i));
  }
 
  //除此之外,還可以進行組合運算
  //新function
  Function<String, String> function2 = new Function<String, String>() {
   @Override
   public String apply(String s) {
    return s.toUpperCase();
   }
  };
  //重新定義一個function3,將function1和function2組合在一起
  //使用Functions的compose方法
  Function<Company, String> function3 = Functions.compose(function2, function1);
  //轉換集合
  Collection<String> upperLocationList = Collections2.transform(company.getCompanies(), function3);
  System.out.println(upperLocationList.contains("ZHUHAI"));
 
  //還有map方法
  Map<Company, String> map = Maps.newHashMap();
  map.put(company.getCompanies().get(0), "bigCompany");
  //function4
  Function<Company, String> function4 = Functions.forMap(map,"UNKNOWN");
  //進行對映,即若有zhuhai這個物件,則返回bigCompany這個值
  //如果物件沒有對應的map value,則返回default value "UNKNOWN"
  Collection<String> types = Collections2.transform(company.getCompanies(), function4);
  Iterator typeIterator = types.iterator();
  while(typeIterator.hasNext()){
   System.out.println(typeIterator.next());
  }
 }
}

上述例子主要實現了Function的主功能,把一個集合類companies從Company類轉換為String型別,利用了guava包中的集合工具類都有的transform方法,通過傳入原始集合和function例項,生成新的集合,只要實現了function介面類中的apply方法就可以了,其中泛型中第一個引數是原始集合的型別,第二個引數是目的集合的型別。還可以使用對應的工具類Functions的compose方法進行組合的Function運算,應對複雜的演算法邏輯。同時,還有對應map方法,通過Functions的forMap方法,將map中value值通過function轉換為新的collection。

Predicate類,與Function類類似,這裡也提供一個PredicateTest來進行測試。
package rich.base;

import java.util.Collection;
import java.util.Iterator;

import rich.model.Company;

import com.google.common.base.Functions;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.collect.Collections2;

public class PredicateTest {

 public static void main(String[] args) {
  //Predicate主要用於對Collection的值進行過濾
  Predicate<Company> predicate1 = new Predicate<Company>(){
   @Override
   public boolean apply(Company company) {
    if(company.getName() == "quest") {
     return true;
    } else
     return false;
   }
  };
  Company company = new Company();
  company.init();
  //進行過濾
  Collection<Company> companyList1 = Collections2.filter(company.getCompanies(), predicate1);
  Iterator<Company> c1 = companyList1.iterator();
 while(c1.hasNext()) {
   System.out.println(c1.next().getLocation());
  }
 
  //有一個Predicates類用於對Predicate介面進行操作,用法與Functions類似
  Predicate<Company> predicate2 = new Predicate<Company>(){
   @Override
   public boolean apply(Company company) {
    if(company.getLocation() == "zhuhai") {
     return true;
    } else
     return false;
   }
  };
 
  //and 和 or
  Predicate<Company> predicateOr = Predicates.or(predicate1, predicate2);
  //Predicate<Company> predicateOr = Predicates.and(predicate1, predicate2);
  Collection<Company> companyList2 = Collections2.filter(company.getCompanies(), predicateOr);
  Iterator<Company> c2 = companyList2.iterator();
  while(c2.hasNext()) {
   System.out.println(c2.next().getLocation());
  }
 
  //構造簡易的Predicate過濾集
  Collection<Company> companyList3 = Collections2.filter(company.getCompanies(), Predicates.notNull());
  //Collection<Company> companyList4 = Collections2.filter(company.getCompanies(), Predicates.alwaysTrue());
 }
}

與Function介面類似,Predicate介面類也是需要實現其apply的方法,並使用Guava包中集合工具類的filter方法對集合元素進行過濾。當然,也提供對應的工具類Predicates的and,or,not等方法進行復雜邏輯的過濾,並提供諸如Predicates.notNull或Predicates.alwaysTrue等簡單的predicate例項方法。


下面貼出我看的兩個包Base包和collect包和其測試方法。僅供參考,如有問題,請留言,我會盡快回復。

Base包:

ObjectsTest

package rich.base;

import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import com.google.common.base.Joiner;
import com.google.common.base.MoreObjects;
import com.google.common.base.Objects;
import com.google.common.base.Splitter;
import com.google.common.base.Strings;
/*
 * base 包大多是用於判斷值是否為空和判斷相等的方法集合包
 */
public class ObjectsTest {


 public static void main(String[] args) {
  
  //Objects
  //判斷兩個物件是否相等。
   System.out.println(Objects.equal("1", "2"));
  //Objects的方法都移到了MoreObject上
  //一般是用來判斷第一個引數值是否為空,若為空,則返回第二個引數的值。
  System.out.println(MoreObjects.firstNonNull(null, 2));	 
  //StringHelper是moreOjbects的靜態內部類,使用MoreObjects.toStringHelper獲得
  MoreObjects.ToStringHelper stringHelper = MoreObjects.toStringHelper("MyObject").add("a", 1);
  System.out.println(stringHelper);
  
  //Strings
  //判斷string為null或者“”
  System.out.println(Strings.isNullOrEmpty(""));
  //將空的string轉變為null物件,相對應的有nullToEmpty
  System.out.println(Strings.emptyToNull(""));
  //重複String
  System.out.println(Strings.repeat("abc", 5));
  
  
  //Joiner 
  //String有split方法,但String陣列沒有join方法
  String[] joinStrArray = new String[]{"abc","bdc","dfg" };
  //沒有迴圈的join方法, 還可以用skipNulls方法剔除null objects
  Joiner joiner = Joiner.on(",");
  String joinerString = joiner.join(joinStrArray);
  //for(int i = 0; i < joinStrArray.size(); i++) { String joinerStr += (joinStrArray[i] + ",") } 更優雅一些,right? 
  System.out.println(joinerString);
  //使用MapJoin
  Map<String, String> joinMapArray = new HashMap<String, String>();
  joinMapArray.put("lu", "rich");
  joinMapArray.put("hong", "alex");
  joinMapArray.put("wang", "sinba");
  Joiner.MapJoiner mapJoiner = joiner.withKeyValueSeparator("-");
  System.out.println(mapJoiner.join(joinMapArray));
  //還可以加到StringBuilder中,不展開
  //joinerString.split(",");是陣列
  //Splitter 
  Splitter splitter = Splitter.on(",").trimResults();
  //拿回上面使用的joinerString
  Iterable<String> splitterStrArray = splitter.split(joinerString);
  Iterator<String> iterator = splitterStrArray.iterator();
  while(iterator.hasNext()) {
   System.out.println(iterator.next());
  }
  //感覺原方法更好一些。
//	 String[] test = joinerString.split(",");
//	 for(int i = 0; i < test.length; i++) {
//	 System.out.println(test[i]);
//	 }
  //Splitter也有mapSplitter方法
  Splitter.MapSplitter mapSplitter = splitter.withKeyValueSeparator("-");
  Map<String, String> mapSplitterArray = mapSplitter.split(mapJoiner.join(joinMapArray));
  Collection<String> collectMap = mapSplitterArray.values();
  Iterator<String> c = collectMap.iterator();
  while(c.hasNext()) {
   System.out.println(c.next());
  }
 }
}

PreconditionsTest
package rich.base;

import rich.model.Company;

import com.google.common.base.Preconditions;

public class PreconditionsTest {


 public static void main(String[] args) {

  Company company = new Company();
  company.init();
  //Preconditions用來檢查引數值是否符合預期
  Preconditions.checkNotNull(company.getCompanies().get(0), "Check whether has a null object");
  //如果為null值,則會拋exception,並提示errorMessage
  Preconditions.checkNotNull(null, "this is a null object");
  Preconditions.checkArgument(1 < 0, "this is a wrong answer.");
  //陣列下標少於size
  Preconditions.checkElementIndex(3, company.getCompanies().size());
 }
}

Collection包:

ListsTest

package rich.collect;

import java.util.ArrayList;
import java.util.List;

import rich.model.Company;

import com.google.common.base.Function;
import com.google.common.collect.Lists;

public class ListsTest {

 public static void main(String[] args) {
  //分配一個arrayList 方法與
  //List<Company> companies = new ArrayList<Company>();
  //一樣
  List<Company> companies = Lists.newArrayList();
  //還可以指定初始大小
  //List<Company> companies = Lists.newArrayListWithCapacity(10);
  //List<Company> companies = Lists.newArrayListWithExpectedSize(20);
  companies.add(Company.newCompany("oracle", "shenzhen"));
  companies.add(Company.newCompany("tecent", "shenzhen"));
  
  //建立LinkedList
  List<Company> companies2 = Lists.newLinkedList();
  
  //reverse list
  List<Company> reverseCompanyList = Lists.reverse(companies);
  //將list切分成大小為1的list陣列返回
  List<List<Company>> partitionCompanyList = Lists.partition(companies, 1);
  //複製一個list
  List<Company> copyCompanyList = Lists.newCopyOnWriteArrayList(companies);
  System.out.println();
  //Arrays.asList()
  String[] testList = {"acb","bdc"};
  //可以繼續加單個object到list中,並對陣列進行list轉換
  List<String> transformList = Lists.asList("dd", testList);
  System.out.println(transformList.contains("dd"));
  //transform方法配合function類使用
  Function<Company, String> functionList = new Function<Company, String>() {
   @Override
   public String apply(Company company) {	 
    return company.getName();
   }
  };
  Lists.transform(companies, functionList);
  //沒有filter方法
 }
}

SetsTest
package rich.collect;

import java.util.Set;

import rich.model.Company;

import com.google.common.base.Predicate;
import com.google.common.collect.Sets;

public class SetsTest {


 public static void main(String[] args) {
  Company company = new Company();
  company.init();
  //Set 方法與list類似,只是物件集元素不重複
  Set<Company> companySet = Sets.newHashSet();
  companySet.addAll(company.getCompanies());
  //newTreeSet,newLinkedHashSet()
  Predicate<Company> predicate = new Predicate<Company>() {
   @Override
   public boolean apply(Company company) {
    if(company.getName().equals("dell")) return false;
    return true;
   }
  };
  Set<Company> filterSet = Sets.filter(companySet, predicate);
  System.out.println(filterSet.contains(company.getCompanies().get(1)));
 } 
} 

MapsTest
package rich.collect;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import rich.model.Company;

import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.collect.Maps;

public class MapsTest {


 public static void main(String[] args) {
  Company company = new Company();
  company.init();
  List<Company> companies = company.getCompanies();
  //Maps 建立一個map
  Map<Company, String> companyMap = Maps.newHashMap();
  //Map<Company, String> companyMapUtil = new HashMap<Company, String>();
  companyMap.put(companies.get(0), "subsidiary");
  companyMap.put(companies.get(1), "parentCompany");
  //與Lists類似,可以建立expectedSize的
  Map<Company, String> companyMap1 = Maps.newHashMapWithExpectedSize(10);
  //也有newLinkHashMap,newTreeMap和newEnumMap
  //同樣的,也可以使用Function和Predicate類進行轉換和過濾
  //Function
  Function<String, String> function = new Function<String, String>() {
   @Override
   public String apply(String relation) {
    return relation + " is wrapped";
   }
  };
  Map<Company, String> transformMap = Maps.transformValues(companyMap, function);
  System.out.println(transformMap.containsValue("subsidiary is wrapped"));
  
  //Predicate
  Predicate<String> valuePredicate= new Predicate<String>() {
   @Override
   public boolean apply(String relation) {
    if(relation.equals("UNKNOWN")) return false;
    return true;
   }
   
  };
  companyMap.put(Company.newCompany("oracle", "shenzhen"), "UNKNOWN");
  Map<Company, String> filterValueMap = Maps.filterValues(companyMap, valuePredicate);
  System.out.println(filterValueMap.containsValue("UNKNOWN"));
  //除了value filter,還可以key filter,方法類似,不展開
 }
}

IteralbesTest
package rich.collect;

import java.util.List;

import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;

import rich.model.Company;

public class IterablesTest {

 public static void main(String[] args) {
  //Iterables擴充套件iterable集合類方法
  Company company = new Company();
  company.init();
  //concat方法,串聯list,set,vector等集合類
  List<Company> newCompanyList = Lists.newArrayList();
  newCompanyList.add(Company.newCompany("oracle", "shenzhen"));
  newCompanyList.add(Company.newCompany("tecent", "shenzhen"));
  Iterable iterablesList = Iterables.concat(newCompanyList, company.getCompanies());
  
  //集合類方法,一般都會有function和Predicate方法。
  //就是transform和filter方法,不展開
  //但說一說find方法,find方法是找到第一個符合條件的value返回
  Predicate<Company> predicate = new Predicate<Company>() {
   @Override
   public boolean apply(Company company) {
    return company.getName() == "quest";
   }
  };
  
  Company matchCompany = Iterables.find(iterablesList, predicate);
  //因為如果找不到值的話,會報異常,所以一般會使用加defaultValue的find方法
  Company matchCompany1 = Iterables.find(iterablesList, predicate, Company.newCompany("emc", "shanghai"));
  if(matchCompany != null) {
   System.out.println(matchCompany.getName());
  }
  //iterable是沒有size的方法,所以可以使用Iterables.size()方法
  System.out.println(Iterables.size(iterablesList));
  //還有就是getFirst和getLast方法,toArray方法,isEmpty方法等等,不展開
 }
}

OrdingTest
package rich.collect;

import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;

import rich.model.Company;

import com.google.common.collect.ComparisonChain;
import com.google.common.collect.Ordering;


public class OrderingTest {


 public static void main(String[] args) {
  //Ordering類,實現Comparator介面
  Ordering<Company> ordering = new Ordering<Company>() {
   @Override
   public int compare(Company company1, Company company2) {
    return company1.getName().length() - company2.getName().length(); 
   }
  };
  
  //使用compound方法,組合解決Comparator介面
  Comparator<Company> comparator1 = new Comparator<Company>() {
   @Override
   public int compare(Company o1, Company o2) {
    return o1.getLocation().length() - o1.getLocation().length();
   }
  };
  
  Comparator<Company> comparator2 = new Comparator<Company>() {
   @Override
   public int compare(Company o1, Company o2) {
    return o1.getName().length() - o1.getName().length();
   }
  };
  
  Ordering<Company> ordering2 = Ordering.compound(Arrays.asList(comparator1, comparator2));
  //進行排序
  Company company = new Company();
  company.init();
  Collections.sort(company.getCompanies(), ordering2);
  
 }
}

SpecificalMapTest有趣的方法都在這裡了,請詳閱

SpecificalMapTest

package rich.collect;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import com.google.common.collect.HashBiMap;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.HashMultiset;
import com.google.common.collect.Multimap;
import com.google.common.collect.Multiset;

public class SpecificalMapTest {


 public static void main(String[] args) {
  //Multiset 把重複元素的放入集合
  //可以用於統計重複元素的數量
  //例如有一個list裡面有各種字串,你要統計每個字串在list裡面出現的次數,偏向於一個bag的概念
  List<String> wordList = getWordList();	
//	 Map<String, Integer> map = new HashMap<String, Integer>(); 
//	 for(String word : wordList){ 
//	 Integer count = map.get(word); 
//	 map.put(word, (count == null) ? 1 : count + 1); 
//	 } 
//	 Integer count = map.get("a");
  //Multiset用法
  Multiset<String> multiSet = HashMultiset.create();
  multiSet.addAll(wordList);
  int count = multiSet.count("a");
  System.out.println(count + "--" + multiSet.size());
  multiSet.setCount("a", 5);
  System.out.println(multiSet.count("a") + "--" + multiSet.size());
  
  //Multimap 在Map中value裡面放多個元素
  //Map 的值像{k1=v1,k2=v2,...} Multimap像{k1=[v1,v2,v3],k2=[v4,v5],...}
  //當然我們也可以這樣構建一個物件,這也是可以的,但顯得有些麻煩
  HashMap<String, HashSet<String>> map = new HashMap<String, HashSet<String>>();
  //Multimap用法,與上面等價
  Multimap<String, String> hashMultimap = HashMultimap.create(); //HashSet不能儲存相同value元素,繼承SetMultimap
  hashMultimap.put("dell", "zhuhai");
  hashMultimap.put("dell", "shanghai");
  hashMultimap.put("dell", "shanghai");
  Collection<String> mapCollection = hashMultimap.get("dell");
  Iterator c = mapCollection.iterator();
  while(c.hasNext()) {
   System.out.println(c.next());
  }
  //除了HashMultimap,還有ArrayListMultimap,LinkedHashMultimap,TreeMultimap,ImmutableMultimap 不展開
  
  //BiMap value和key都不能重複 可以根據value推斷key值
  //也可以key和value互換
  HashBiMap<String, String> biMap = HashBiMap.create();
  biMap.inverse();
  //RangeMap

 }
 
 public static List<String> getWordList() {
  List<String> wordList = new ArrayList<String>();
  wordList.add("a");
  wordList.add("ab");
  wordList.add("ab");
  wordList.add("a");
  wordList.add("a");
  wordList.add("c");
  return wordList;
 }
}

Primitive包

PrimitivesTest

package rich.primitive;

import java.util.Collections;
import java.util.List;

import com.google.common.collect.Lists;
import com.google.common.primitives.Doubles;

public class PrimitivesTest {


 public static void main(String[] args) {
  //Double,float,int,boolean等等
  //Double.valueOf("12.2bb");
  Double.parseDouble("");
  //用這種方法的主要原因是因為錯誤的時候不會丟擲exception,如果錯誤的時候返回的是null值
  Doubles.tryParse("12.0bb");
  
  double[] abc = {12.0,52.1};
   Doubles.max(abc);
   Doubles.min(abc);
   
   //當然你也可以使用Collection的max和min方法。不用重寫comparator
   List<Integer> testCollection = Lists.newArrayList();
  testCollection.add(2);
  testCollection.add(1);
  testCollection.add(3);
  System.out.println(Collections.max(testCollection));
  
   //陣列是否有12.0這個值
   Doubles.contains(abc, 12.0);
   //陣列和集合的轉換
   //asList和toArray方法
   //indexOf和lastIndexOf方法
 }
}


guava中文 api(不全)
the latest version: guava-18.0.jar about guava api