天天看点

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工具类
Collection JDK Collections2不要和java.util.Collections混淆
List Lists
Set Sets
SortedSet
Map Maps
SortedMap
Queue Queues
Multiset Guava Multisets
Multimap Multimaps
BiMap
Table Tables
  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