一、简介

Guava是一个开源的Java库,它提供了许多用于集合(collections)、字符串处理(string processing)、缓存(caching)、并发(concurrency)等的很有用的方法,可以方便编程,提高效率。

二、安装

Guava的Maven配置:

<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>27.1-jre</version>
</dependency>

三、常用方法

1、基本工具

  • 前置条件(Preconditions)

可以使用Preconditions类的静态方法来检查调用函数的参数值是否合适。

import com.google.common.base.Preconditions;
public class Math {
	public Integer div(Integer a, Integer b){
		Preconditions.checkNotNull(a, "Dividend can't be null!");
		Preconditions.checkNotNull(b, "Divisor can't be null!");
		Preconditions.checkArgument(b > 0, "Argument 'b' was %s but expected positive", b);
		return a / b;
	}
}

math.div(null, null);

java.lang.NullPointerException: Dividend can't be null!
	at com.google.common.base.Preconditions.checkNotNull(Preconditions.java:897)
	at com.mycompany.app.test.Math.div(Math.java:8)

math.div(8, 0);

java.lang.IllegalArgumentException: Argument 'b' was 0 but expected positive
	at com.google.common.base.Preconditions.checkArgument(Preconditions.java:217)
	at com.mycompany.app.test.Math.div(Math.java:10)
  • Optional

Optional<T>可以表示一个可能为null的T类型的引用,一个Optional实例用存在或缺失来表示是否包含非null对象的引用。

Optional<String> optional = Optional.of(null);
System.out.println(optional.isPresent());//java.lang.NullPointerException
Optional<String> optional = Optional.fromNullable(null);
System.out.println(optional.isPresent());//false
Optional<String> optional = Optional.of("Hello World!");
System.out.println(optional.isPresent());//true
if(optional.isPresent()){
	System.out.println(optional.get());//Hello World!
}
  • Objects
System.out.println(Objects.equal("Hi", "Hi"));//true
System.out.println(Objects.equal(null, null));//true
System.out.println(Objects.equal(null, "Hi"));//false
System.out.println(Objects.equal("Hi", null));//false
  • Ordering

Ordering是一个特殊的Comparator实例,它提供了链式调用方法来定制和增强现有的比较器,可以使用Ordering类来构建复杂的比较器。

Ordering<String> ordering = Ordering.natural();
		
List<String> names = new ArrayList<String>();
names.add("Sophie");
names.add("James");
names.add("Jennifer");
names.add("Karen");
names.add("Stan Lee");

System.out.println(ordering.isOrdered(names));//false

Collections.sort(names, ordering);
System.out.println(names);//[James, Jennifer, Karen, Sophie, Stan Lee]

System.out.println(ordering.isOrdered(names));//true

Collections.sort(names, ordering.reverse());
System.out.println(names);//[Stan Lee, Sophie, Karen, Jennifer, James]

names.add(null);

Collections.sort(names, ordering.nullsFirst());
System.out.println(names);//[null, James, Jennifer, Karen, Sophie, Stan Lee]

2、区间

Range表示一个区间或序列:

//创建不同区间类型的Range

//0<=x<=5
Range<Integer> range = Range.closed(0, 5);
//0<x<5 
range = Range.open(0, 5);
//0<x<=5
range = Range.openClosed(0, 5);
//0<=x<5
range = Range.closedOpen(0, 5);
//x>=5
range = Range.greaterThan(5);
//x<=5
range = Range.atMost(5);
Range<Integer> range1 = Range.closed(0, 5);
Range<Integer> range2 = Range.open(3, 8);
System.out.println(range1);//[0..5]
System.out.println(range2);//(3..8)

System.out.println(range1.intersection(range2));//(3..5]
System.out.println(range2.contains(3));//false
System.out.println(range1.lowerEndpoint() + " " + range1.upperEndpoint());//0 5
System.out.println(Range.openClosed(6, 6).isEmpty());//true
//是否相连
System.out.println(Range.closed(0, 5).isConnected(Range.open(5, 10)));//true
//span方法返回包括两个参数区间的最小区间
System.out.println(Range.closed(3, 5).span(Range.open(8, 10)));//[3..10)

3、集合

  • 不可变集合

创建对象的不可变拷贝是一种很好的防御性编程技巧,不可变对象在被其他库调用或多线程调用时,由于是不可变的,所以是安全的。

通常用copyOfofbuilder方法创建:

Set<String> set = new HashSet<String>();
set.add("A");
set.add("C");

ImmutableSet<String> immutableSet = ImmutableSet.copyOf(set);
System.out.println(immutableSet);//[A, C]

ImmutableMap<String, String> immutableMap = ImmutableMap.of("name", "Jack", "age", "30");
System.out.println(immutableMap);//{name=Jack, age=30}

immutableSet = ImmutableSet.<String>builder().add("foo").add("bar").build();
System.out.println(immutableSet);//[foo, bar]

可以看到ImmutableCollection抽象类中的add、remove等方法都会直接抛异常:

  • 新集合类型

    • Multiset

    Multiset允许添加相同的元素,并提供了处理这些重复元素相关的方法。

      Multiset<String> multiset = HashMultiset.create();
      multiset.add("a");
      multiset.add("b");
      multiset.add("c");
      multiset.add("a");
      multiset.add("c");
    
      //统计a出现的次数
      System.out.println("Occurrence of 'a':" + multiset.count("a"));//Occurrence of 'a':2
    
      //分别打印每种元素出现的次数
      for(Entry<String> entry : multiset.entrySet()){
          System.out.println(String.format("Occurrence of '%s':%s", entry.getElement(), entry.getCount()));
      }
    
      Occurrence of 'a':2
      Occurrence of 'b':1
      Occurrence of 'c':2
    
    • Multimap

    Multimap允许一个key对应多个value,类似于Map<K, Collection<V>>

      Multimap<String, String> multimap = ArrayListMultimap.create();
      multimap.put("fruit", "apple");
      multimap.put("fruit", "mango");
      multimap.put("fruit", "coconut");
      multimap.put("fruit", "strawberry");
    	
      multimap.put("animal", "cat");
      multimap.put("animal", "dog");
      multimap.put("animal", "fish");
    	
      Collection<String> fruits = multimap.get("fruit");
      System.out.println(fruits);//[apple, mango, coconut, strawberry]
      fruits.add("pineapple");
    	
      Map<String, Collection<String>> map = multimap.asMap();
      System.out.println(map);//{fruit=[apple, mango, coconut, strawberry, pineapple], animal=[cat, dog, fish]}
    	
      for(Entry<String, Collection<String>> entry : map.entrySet()){
          System.out.println(String.format("Key: %s, Value: %s", entry.getKey(), entry.getValue()));
      }
      //Key: fruit, Value: [apple, mango, coconut, strawberry, pineapple]
      //Key: animal, Value: [cat, dog, fish]
    
    • BiMap

    可以使用BiMap实现键值对的双向映射(key和value都是唯一的):

      BiMap<String, Integer> biMap = HashBiMap.create();
      //name -- id
      biMap.put("Bob", 101);
      //get username by id 
      System.out.println(biMap.inverse().get(101));//Bob
    
    • Table

    Table支持使用多个键作索引,并提供多种视图供使用:

      /*
       * ID   Name     Sex
       * 001  Fanny    female
       * 002  Charles  male
       */
      Table<Integer, String, String> table = HashBasedTable.create();
      table.put(1, "ID", "001");
      table.put(1, "Name", "Fanny");
      table.put(1, "Sex", "female");
      table.put(2, "ID", "002");
      table.put(2, "Name", "Charles");
      table.put(2, "Sex", "male");
    	
      System.out.println(table.row(1));//{ID=001, Name=Fanny, Sex=female}
      System.out.println(table.row(2));//{ID=002, Name=Charles, Sex=male}
      System.out.println(table.column("ID"));//{1=001, 2=002}
      System.out.println(table.get(2, "Name"));//Charles
    
    • RangeSet

    RangeSet表示一组不相连的非空区间,如果把一个区间添加到可变的RangeSet时,所有相连的区间会被合并(空区间会被忽略):

      RangeSet<Integer> rangeSet = TreeRangeSet.create();
      rangeSet.add(Range.closed(1, 3));//[1..3]
      rangeSet.add(Range.closedOpen(5, 8));//[5..8)
      rangeSet.add(Range.openClosed(4, 4));//空区间
      rangeSet.add(Range.closedOpen(8, 20));//[8..20)
      System.out.println(rangeSet);//[[1..3], [5..20)]
      rangeSet.remove(Range.open(2, 10));
      System.out.println(rangeSet);//[[1..2], [10..20)]
    
    • RangeMap

    RangeMap表示不相交的非空区间到特定值的映射,与RangeSet不同,RangeMap不会合并相邻的映射:

      RangeMap<Integer, String> rangeMap = TreeRangeMap.create();
      rangeMap.put(Range.closed(0, 60), "seven students");
      rangeMap.put(Range.openClosed(60, 80), "seven students");
      rangeMap.put(Range.open(80, 100), "ten students");
    	
      System.out.println(rangeMap);
      rangeMap.remove(Range.closed(75, 95));
      System.out.println(rangeMap);
    
      [[0..60]=seven students, (60..80]=seven students, (80..100)=ten students]
      [[0..60]=seven students, (60..75)=seven students, (95..100)=ten students]
    
  • 集合工具类

    • Lists

    Lists为List类型的对象提供了一些工具方法:

      List<Integer> nums = Ints.asList(1, 3, 2, 4, 7, 5, 9);
      //反转
      System.out.println(Lists.reverse(nums));//[9, 5, 7, 4, 2, 3, 1]
      //按指定大小分割
      System.out.println(Lists.partition(nums, 3));//[[1, 3, 2], [4, 7, 5], [9]]
    
    • Sets

    Sets提供了很多标准的集合运算方法,例如:交集、并集、差集等,这些方法接受Set类型的参数并返回SetView对象,SetView对象可以直接当作Set来使用,也可以调用其copyInto(Set)方法拷贝到另一个可变集合中或者调用其immutableCopy()方法做不可变拷贝。

      Set<String> set1 = Sets.newHashSet("A", "B", "C", "D");
      Set<String> set2 = Sets.newHashSet("X", "Y", "C", "D");
      //并集
      System.out.println(Sets.union(set1, set2));//[A, B, C, D, X, Y]
      //交集
      System.out.println(Sets.intersection(set1, set2));//[C, D]
      //差集:set1与set2相比
      System.out.println(Sets.difference(set1, set2));//[A, B]
      //差集:set2与set1相比
      System.out.println(Sets.difference(set2, set1));//[X, Y]
      //只在两个集合其中之一的元素组成的集合
      System.out.println(Sets.symmetricDifference(set1, set2));//[A, B, X, Y]
    
    • Maps

    Maps为Map对象提供了一些工具方法:

    如果想要对一组对象(这些对象的某个属性值是唯一的),按某个唯一值属性查找,则可以使用Maps.uniqueIndex()方法:

      List<String> values = Lists.newArrayList("I", "He", "You", "They");
      ImmutableMap<Integer, String> stringsByIndex = Maps.uniqueIndex(values, new Function<String, Integer>() {
          public Integer apply(String input) {
              return input.length();
          }
      });
      System.out.println(stringsByIndex.get(1));
      System.out.println(stringsByIndex.get(3));
    

    Maps.difference(Map, Map)方法用来比较两个Map的不同点:

      Map<String, Integer> left = ImmutableMap.of("a", 1, "b", 2, "c", 3);
      Map<String, Integer> right = ImmutableMap.of("x", 7, "b", 2, "c", 10);
      MapDifference<String, Integer> diff = Maps.difference(left, right);
      //key和value都相同的项
      System.out.println(diff.entriesInCommon());//{b=2}
      //key只在左边Map的项
      System.out.println(diff.entriesOnlyOnLeft());//{a=1}
      //key只在右边Map的项
      System.out.println(diff.entriesOnlyOnRight());//{x=7}
      //key相同但value不同的项
      Map<String, ValueDifference<Integer>> differing = diff.entriesDiffering();
      System.out.println(differing);//{c=(3, 10)}
    
  • 扩展工具类

可以使用Iterators.peekingIterator(Iterator)将Iterator包装为PeekingIterator,此类提供了peek()方法可以获取下一次调用next()方法的返回值:

List<String> arr = Lists.newArrayList();
arr.add("A");
arr.add("B");
arr.add("B");
arr.add("B");
arr.add("C");
PeekingIterator<String> iter = Iterators.peekingIterator(arr.iterator());
//打印集合时跳过相邻且重复的元素
while(iter.hasNext()){
	String current = iter.next();
	while(iter.hasNext() && iter.peek().equals(current)){
		iter.next();
	}
	System.out.println(current);
}
A
B
C

4、字符串处理

  • 连接器

可以使用Joiner将字符串用指定的连接符连接起来(Joiner实例都是不可变的,因此是线程安全的):

String[] parts = new String[]{"Tom", "Lucy", null, "Jack"};
Joiner joiner = Joiner.on(" - ").skipNulls();
System.out.println(joiner.join(parts));//Tom - Lucy - Jack

String ret = Joiner.on(" ").join(Arrays.asList(1, 3, 4, 5, 8, 7));
System.out.println(ret);//1 3 4 5 8 7
  • 拆分器(Splitter)

Splitter支持按单个字符、正则表达式、固定长度做拆分,同时可以对拆分结果做处理:

String words = "foo,bar,hi,   hello, ,world,";
//使用split
System.out.println(Arrays.asList(words.split(",")));//[foo, bar, hi,    hello,  , world]

Splitter splitter = Splitter.on(",");
System.out.println(splitter.split(words));//[foo, bar, hi,    hello,  , world, ]
System.out.println(splitter.trimResults().split(words));//[foo, bar, hi, hello, , world, ]
System.out.println(splitter.trimResults().omitEmptyStrings().split(words));//[foo, bar, hi, hello, world]
  • 字符匹配器

CharMatcher实例代表某一类字符(数字或空白字符),它提供了一系列方法来对字符作特定的操作:trim(修剪)、collapse(折叠)、remove(移除)、retain(保留)等。

//去除空白字符
System.out.println(CharMatcher.whitespace().removeFrom(" a b c d e "));//abcde
//统计字符出现的次数
System.out.println(CharMatcher.anyOf("abc").countIn("I am a student, I want be a teacher!"));//7
//字符串中不是'-'的部分都替换为'X'
System.out.println(CharMatcher.isNot('-').replaceFrom("I-Love-You", "X"));//X-XXXX-XXX
  • 大小写格式

CaseFormat可以很方便在命名规范或大小写规则间转换字符串:

System.out.println(CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.UPPER_UNDERSCORE, "const_name"));//CONST_NAME

System.out.println(CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.LOWER_CAMEL, "const_name"));//constName

System.out.println(CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.UPPER_CAMEL, "const_name"));//ConstName

System.out.println(CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.LOWER_HYPHEN, "const_name"));//const-name
附:

Guava API

Guava Wiki

Google Guava官方教程(中文版)

Guava教程

Maven Repository: Guava