Google Guava 库用法整理

12年前
参考:
http://codemunchies.com/2009/10/beautiful-code-with-google-collections-guava-and-static-imports-part-1/ (2,3,4)
http://blog.publicobject.com

更多用法参考http://ajoo.iteye.com/category/119082

以前这么用:
Map<String, Map<Long, List<String>>> map = new HashMap<String, Map<Long,List<String>>>();

现在这么用(JDK7将实现该功能):
Map<String, Map<Long, List<String>>> map = Maps.newHashMap();


针对不可变集合:
以前这么用:
List<String> list = new ArrayList<String>();  list.add("a");  list.add("b");  list.add("c");  list.add("d");

现在Guava这么用:
ImmutableList<String> of = ImmutableList.of("a", "b", "c", "d");  ImmutableMap<String,String> map = ImmutableMap.of("key1", "value1", "key2", "value2");


文本文件读取现在Guava这么用
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();  }


基本类型比较, 现在Guava这么用:
int compare = Ints.compare(a, b);


Guava中CharMatcher的用法:
assertEquals("89983", CharMatcher.DIGIT.retainFrom("some text 89983 and more"))  assertEquals("some text  and more", CharMatcher.DIGIT.removeFrom("some text 89983 and more"))


Guava中Joiner的用法:
int[] numbers = { 1, 2, 3, 4, 5 };  String numbersAsString = Joiner.on(";").join(Ints.asList(numbers));

另一种写法:
String numbersAsStringDirectly = Ints.join(";", numbers);


Guava中Splitter的用法:
Iterable split = Splitter.on(",").split(numbsAsString);

对于这样的字符串进行切分:
String testString = "foo , what,,,more,";  Iterable<String> split = Splitter.on(",").omitEmptyStrings().trimResults().split(testString);


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);


集合
set的交集, 并集, 差集的用法(http://publicobject.com/2008/08/coding-in-small-with-google-collections.html)
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);


针对Map的用法:
MapDifference differenceMap = Maps.difference(mapA, mapB);    differenceMap.areEqual();  Map entriesDiffering = differenceMap.entriesDiffering();  Map entriesOnlyOnLeft = differenceMap.entriesOnlyOnLeft();  Map entriesOnlyOnRight = differenceMap.entriesOnlyOnRight();  Map entriesInCommon = differenceMap.entriesInCommon();


验证与条件检查
原来的写法:
if (count <= 0) {                                                                                               throw new IllegalArgumentException("must be positive: " + count);         }        
           
Guava的写法(Jakarta Commons中有类似的方法):
Preconditions.checkArgument(count > 0, "must be positive: %s", count);


一个更酷的用法:
public PostExample(final String title, final Date date, final String author) {      this.title = checkNotNull(title);      this.date = checkNotNull(date);      this.author = checkNotNull(author);  }


如果一个key对应多个value的Map, 你会怎么处理? 如果还在使用Map<K, List<V>>的话, 你就out了
使用MultiMap吧:
Multimap<Person, BlogPost> multimap = ArrayListMultimap.create();


Multimap的另一个使用场景:
比如有一个文章数据的map:
List<Map<String, String>> listOfMaps = mapOf("type", "blog", "id", "292", "author", "john");

如果要按照type分组生成一个List
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");                                                                                   }                                                                                                                     }); 
                                                                                                    
针对集合中只有一个元素的情况:
Iterables.getOnlyElement();
这个主要是用来替换Set.iterator.next()或 List.get(0), 而且在测试中使用非常方便, 如果出现0个或者2+则直接抛出异常

比较的最大最小值:
Comparators.max
Comparators.min

equals和hashcode的用法:
  public boolean equals(Object o) {      if (o instanceof Order) {        Order that = (Order)o;          return Objects.equal(address, that.address)            && Objects.equal(targetArrivalDate, that.targetArrivalDate)            && Objects.equal(lineItems, that.lineItems);      } else {        return false;      }    }      public int hashCode() {      return Objects.hashCode(address, targetArrivalDate, lineItems);    }


ImmutableList.copyOf的用法:
以前这么用:
  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);    }


Iterables.concat()的用法:
以前这么用:
  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;    }


Constraints.constrainedList: 给List操作注入约束逻辑, 比如添加不合法元素直接报错.
以前这么写:
  private final List<LineItem> purchases = new ArrayList<LineItem>();      /**     * Don't modify this! Instead, call {@link #addPurchase(LineItem)} to add     * new purchases to this order.     */    public List<LineItem> getPurchases() {      return Collections.unmodifiableList(purchases);    }      public void addPurchase(LineItem purchase) {      Preconditions.checkState(catalog.isOffered(getAddress(), purchase.getProduct()));      Preconditions.checkState(purchase.getCharge().getUnits() > 0);      purchases.add(purchase);    }  现在这么写:    private final List<LineItem> purchases = Constraints.constrainedList(        new ArrayList<LineItem>(),        new Constraint<LineItem>() {          public void checkElement(LineItem element) {            Preconditions.checkState(catalog.isOffered(getAddress(), element.getProduct()));            Preconditions.checkState(element.getCharge().getUnits() > 0);          }        });      /**     * Returns the modifiable list of purchases in this order.     */    public List<LineItem> getPurchases() {      return purchases;    }


不允许插入空值的Set(Constraints的用法):
        Set<String> set = Sets.newHashSet();          Set<String> constrainedSet = Constraints.constrainedSet(set, Constraints.notNull());          constrainedSet.add("A");          constrainedSet.add(null); // NullPointerException here


Multimap的用法(允许多值的map):
以前这么写:
  Map<Salesperson, List<Sale>> map = new Hashmap<SalesPerson, List<Sale>>();      public void makeSale(Salesperson salesPerson, Sale sale) {      List<Sale> sales = map.get(salesPerson);      if (sales == null) {        sales = new ArrayList<Sale>();        map.put(salesPerson, sales);      }      sales.add(sale);    }

现在这么写:
  Multimap<Salesperson, Sale> multimap         = new ArrayListMultimap<Salesperson,Sale>();      public void makeSale(Salesperson salesPerson, Sale sale) {      multimap.put(salesperson, sale);    }

以前这么写:
  public Sale getBiggestSale() {      Sale biggestSale = null;      for (List<Sale> sales : map.values()) {        Sale biggestSaleForSalesman            = Collections.max(sales, SALE_COST_COMPARATOR);        if (biggestSale == null            || biggestSaleForSalesman.getCharge() > biggestSale().getCharge()) {          biggestSale = biggestSaleForSalesman;        }      }      return biggestSale;    }

现在这么写(需要将map转换成multimap):
  public Sale getBiggestSale() {      return Collections.max(multimap.values(), SALE_COST_COMPARATOR);    }


Joiner的用法:
以前这样写:
public class ShoppingList {    private List<Item> items = ...;      ...      public String toString() {      StringBuilder stringBuilder = new StringBuilder();      for (Iterator<Item> s = items.iterator(); s.hasNext(); ) {        stringBuilder.append(s.next());        if (s.hasNext()) {          stringBuilder.append(" and ");        }      }      return stringBuilder.toString();    }  }

现在这样写:
public class ShoppingList {   private List<Item> items = ...;     ...     public String toString() {     return Join.join(" and ", items);   }  }


Comparators.fromFunction的用法:
以前这样写:
 public Comparator<Product> createRetailPriceComparator(       final CurrencyConverter currencyConverter) {     return new Comparator<Product>() {       public int compare(Product a, Product b) {         return getRetailPriceInUsd(a).compareTo(getRetailPriceInUsd(b));       }       public Money getRetailPriceInUsd(Product product) {         Money retailPrice = product.getRetailPrice();         return retailPrice.getCurrency() == CurrencyCode.USD             ? retailPrice             : currencyConverter.convert(retailPrice, CurrencyCode.USD);       }     };   }

现在这样写(感觉也没省多少):
 public Comparator<Product> createRetailPriceComparator(       final CurrencyConverter currencyConverter) {     return Comparators.fromFunction(new Function<Product,Money>() {       /** returns the retail price in USD */       public Money apply(Product product) {         Money retailPrice = product.getRetailPrice();         return retailPrice.getCurrency() == CurrencyCode.USD             ? retailPrice             : currencyConverter.convert(retailPrice, CurrencyCode.USD);       }     });   }


BiMap(双向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;      static {     NUMBER_TO_NAME_BIMAP = Maps.newHashBiMap();     NUMBER_TO_NAME_BIMAP.put(1, "Hydrogen");     NUMBER_TO_NAME_BIMAP.put(2, "Helium");     NUMBER_TO_NAME_BIMAP.put(3, "Lithium");   }     public static int getElementNumber(String elementName) {     return NUMBER_TO_NAME_BIMAP.inverse().get(elementName);   }     public static string getElementName(int elementNumber) {     return NUMBER_TO_NAME_BIMAP.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();


关于Strings的一些用法(http://blog.ralscha.ch/?p=888):
assertEquals("test", Strings.emptyToNull("test"));  assertEquals(" ", Strings.emptyToNull(" "));  assertNull(Strings.emptyToNull(""));  assertNull(Strings.emptyToNull(null));     assertFalse(Strings.isNullOrEmpty("test"));  assertFalse(Strings.isNullOrEmpty(" "));  assertTrue(Strings.isNullOrEmpty(""));  assertTrue(Strings.isNullOrEmpty(null));     assertEquals("test", Strings.nullToEmpty("test"));  assertEquals(" ", Strings.nullToEmpty(" "));  assertEquals("", Strings.nullToEmpty(""));  assertEquals("", Strings.nullToEmpty(null));     assertEquals("Ralph_____", Strings.padEnd("Ralph", 10, '_'));  assertEquals("Bob_______", Strings.padEnd("Bob", 10, '_'));     assertEquals("_____Ralph", Strings.padStart("Ralph", 10, '_'));  assertEquals("_______Bob", Strings.padStart("Bob", 10, '_'));    assertEquals("xyxyxyxyxy", Strings.repeat("xy", 5));


Throwables的用法(将检查异常转换成未检查异常):
package com.ociweb.jnb.apr2010;    import com.google.common.base.Throwables;    import java.io.InputStream;  import java.net.URL;    public class ExerciseThrowables {      public static void main(String[] args) {          try {              URL url = new URL("http://ociweb.com");              final InputStream in = url.openStream();              // read from the input stream              in.close();          } catch (Throwable t) {              throw Throwables.propagate(t);          }      }  }


Multimap用法整理(http://jnb.ociweb.com/jnb/jnbApr2008.html):
用来统计多值出现的频率:
        Multimap<Integer, String> siblings = Multimaps.newHashMultimap();          siblings.put(0, "Kenneth");          siblings.put(1, "Joe");          siblings.put(2, "John");          siblings.put(3, "Jerry");          siblings.put(3, "Jay");          siblings.put(5, "Janet");            for (int i = 0; i < 6; i++) {              int freq = siblings.get(i).size();              System.out.printf("%d siblings frequency %d\n", i, freq);          }

输出结果:
引用
        0 siblings frequency 1
        1 siblings frequency 1
        2 siblings frequency 1
        3 siblings frequency 2
        4 siblings frequency 0
        5 siblings frequency 1


Functions(闭包功能)
        Function<String, Integer> strlen = new Function<String, Integer>() {              public Integer apply(String from) {                  Preconditions.checkNotNull(from);                  return from.length();              }          };          List<String> from = Lists.newArrayList("abc", "defg", "hijkl");          List<Integer> to = Lists.transform(from, strlen);          for (int i = 0; i < from.size(); i++) {              System.out.printf("%s has length %d\n", from.get(i), to.get(i));          }      }


不过这种转换是在访问元素的时候才进行, 下面的例子可以说明:
        Function<String, Boolean> isPalindrome = new Function<String, Boolean>() {              public Boolean apply(String from) {                  Preconditions.checkNotNull(from);                  return new StringBuilder(from).reverse().toString().equals(from);              }          };          List<String> from = Lists.newArrayList("rotor", "radar", "hannah", "level", "botox");          List<Boolean> to = Lists.transform(from, isPalindrome);          for (int i = 0; i < from.size(); i++) {              System.out.printf("%s is%sa palindrome\n", from.get(i), to.get(i) ? " " : " NOT ");          }           // changes in the "from" list are reflected in the "to" list          System.out.printf("\nnow replace hannah with megan...\n\n");          from.set(2, "megan");          for (int i = 0; i < from.size(); i++) {              System.out.printf("%s is%sa palindrome\n", from.get(i), to.get(i) ? " " : " NOT ");          }      }