在google guava中为字符串操作提供了很大的便利,有老牌的判断字符串是否为空字符串或者为null,用指定字符填充字符串,以及拆分合并字符串,字符串匹配的判断等等。
 1 //Strings.commonPrefix(a,b) demo 2 String a = "com.jd.coo.Hello"; 3 String b = "com.jd.coo.Hi"; 4 String ourCommonPrefix =Strings.commonPrefix(a,b); 5 System.out.println("a,b common prefix is " +ourCommonPrefix); 6 7 //Strings.commonSuffix(a,b) demo 8 String c = "com.google.Hello"; 9 String d = "com.jd.Hello"; 10 String ourSuffix =Strings.commonSuffix(c,d); 11 System.out.println("c,d common suffix is " + ourSuffix);

 1 int minLength = 4; 2 String padEndResult = Strings.padEnd("123", minLength, '0'); 3 System.out.println("padEndResult is " +padEndResult); 4 5 String padStartResult = Strings.padStart("1", 2, '0'); 6 System.out.println("padStartResult is " + padStartResult);

Splitter类可以方便的根据正则表达式来拆分字符串,可以去掉拆分结果中的空串,可以对拆分后的字串做trim操作,还可以做二次拆分。
我们先看一个基本的拆分例子: Iterable

Splitter的onPattern方法传入的是一个正则表达式,其后紧跟的trimResults()方法表示要对结果做trim,omitEmptyStrings()表示忽略空字符串,split方法会执行拆分操作。
split返回的结果为Iterable
Splitter还有更强大的功能,做二次拆分,这里二次拆分的意思是拆分两次,例如我们可以将a=b;c=d这样的字符串拆分成一个Map

二次拆分首先是使用onPattern做第一次的拆分,然后再通过withKeyValueSeperator('')方法做第二次的拆分。
我们先看一个简单的示例:1 String joinResult = Joiner.on(" ").join(new String[]{"hello","world"}); 2 System.out.println(joinResult);
面例子中我们使用Joiner.on(" ").join(xx)来合并字符串。很简单也很有效。
Splitter方法可以对字符串做二次的拆分,对应的Joiner也可以逆向操作,将Map
使用withKeyValueSeparator方法可以对map做合并。合并的结果是:
a=b,c=d
guava库中还可以对字符串做大小写转换(CaseFormat枚举),可以对字符串做模式匹配。使用起来都很方便。
在开发中经常会需要比较两个对象是否相等,这时候我们需要考虑比较的两个对象是否为null,然后再调用equals方法来比较是否相等,google guava库的com.google.common.base.Objects类提供了一个静态方法equals可以避免我们自己做是否为空的判断,示例如下:1 Object a = null; 2 Object b = newObject(); 3 boolean aEqualsB = Objects.equal(a, b);
Objects.equals的实现是很完美的,其实现代码如下:
1 public static booleanequal(@Nullable Object a, @Nullable Object b) { 2 return a == b || (a != null &&a.equals(b)); 3 }
首先判断a b是否是同一个对象,如果是同一对象,那么直接返回相等,如果不是同一对象再判断a不为null并且a.equals(b). 这样做既考虑了性能也考虑了null空指针的问题。
另外Objects类中还为我们提供了方便的重写toString()方法的机制,我们通过例子来了解一下吧: 1 importcom.google.common.base.Objects; 2 3 public classObjectsDemo { 4 public static voidmain(String [] args) { 5 Student jim = newStudent(); 6 jim.setId(1); 7 jim.setName("Jim"); 8 jim.setAge(13); 9 System.out.println(jim.toString()); 10 } 11 12 public static classStudent { 13 private intid; 14 privateString name; 15 private intage; 16 17 public intgetId() { 18 returnid; 19 } 20 public void setId(intid) { 21 this.id =id; 22 } 23 24 publicString getName() { 25 returnname; 26 } 27 public voidsetName(String name) { 28 this.name =name; 29 } 30 31 public intgetAge() { 32 returnage; 33 } 34 public void setAge(intage) { 35 this.age =age; 36 } 37 38 publicString toString() { 39 return Objects.toStringHelper(this.getClass()) 40 .add("id", id) 41 .add("name", name) 42 .add("age", age) 43 .omitNullValues().toString(); 44 } 45 } 46 }

我们定义了一个Student类,该类有三个属性,分别为id,name,age,我们重写了toString()方法,在这个方法中我们使用了Objects.toStringHelper方法,首先指定toString的类,然后依次add属性名称和属性值,可以使用omitNullValues()方法来指定忽略空值,最后调用其toString()方法,就可以得到一个格式很好的toString实现了。
上面代码输出的结果是:Student{id=1,name=Jim,age=13}
这种方式写起来很简单,可读性也很好,所以用Guava吧。
guava的base包中提供的Preconditions类用来方便的做参数的校验,他主要提供如下方法:
下面我们看一个具体的使用示例: 1 importcom.google.common.base.Preconditions; 2 3 public classPreconditionsDemo { 4 public static voidmain(String[] args) { 5 PreconditionsDemo demo = newPreconditionsDemo(); 6 demo.doSomething("Jim", 19, "hello world, hello java"); 7 } 8 9 public void doSomething(String name, intage, String desc) { 10 Preconditions.checkNotNull(name, "name may not be null"); 11 Preconditions.checkArgument(age >= 18 && age < 99, "age must in range (18,99)"); 12 Preconditions.checkArgument(desc !=null && desc.length() < 10, "desc too long, max length is ", 10); 13 14 //do things 15 } 16 }

上面例子中的doSomething()方法调用了三次Preconditions的方法,来对参数做校验。
看似Preconditions实现很简单,他的意义在于为我们提供了同一的参数校验,并对不同的异常情况抛出合适类型的异常,并对异常信息做格式化。
null会带来很多问题,从开始有null开始有无数程序栽在null的手里,null的含义是不清晰的,检查null在大多数情况下是不得不做的,而我们又在很多时候忘记了对null做检查,在我们的产品真正投入使用的时候,空指针异常出现了,这是一种讨厌的情况。
鉴于此google的guava库中提供了Optional接口来使null快速失败,即在可能为null的对象上做了一层封装,在使用Optional静态方法of时,如果传入的参数为null就抛出NullPointerException异常。
我们看一个实际的例子: 1 importcom.google.common.base.Optional; 2 3 public classOptionalDemo { 4 public static voidmain(String[] args) { 5 Optional

上面的程序,我们使用Optional.of(null)方法,这时候程序会第一时间抛出空指针异常,这可以帮助我们尽早发现问题。
我们再看另外一个例子,我们使用Optional.absent方法来初始化posibleNull实例,然后我们get此对象,看看会是什么情况。 1 public classOptionalDemo { 2 public static voidmain(String[] args) { 3 Optional

运行上面的程序,发现出现了:Exception in thread "main" java.lang.IllegalStateException: Optional.get() cannot be called on an absent value。
这样使用也会有异常出来,那Optional到底有什么意义呢?
使用Optional除了赋予null语义,增加了可读性,最大的优点在于它是一种傻瓜式的防护。Optional迫使你积极思考引用缺失的情况,因为你必须显式地从Optional获取引用。直接使用null很容易让人忘掉某些情形,尽管FindBugs可以帮助查找null相关的问题,但是我们还是认为它并不能准确地定位问题根源。
如同输入参数,方法的返回值也可能是null。和其他人一样,你绝对很可能会忘记别人写的方法method(a,b)会返回一个null,就好像当你实现method(a,b)时,也很可能忘记输入参数a可以为null。将方法的返回类型指定为Optional,也可以迫使调用者思考返回的引用缺失的情形。
guava类库中的Throwables提供了一些异常处理的静态方法,这些方法的从功能上分为两类,一类是帮你抛出异常,另外一类是帮你处理异常。
也许你会想:为什么要帮我们处理异常呢?我们自己不会抛出异常吗?
假定下面的方法是我们要调用的方法。 1 public void doSomething() throwsThrowable { 2 //ignore method body 3 } 4 5 public void doSomethingElse() throwsException { 6 //ignore method body 7 }

这两个方法的签名一个throws出了Throwable另外一个throws出了Exception,他们没有定义具体会抛出什么异常,也就是说他们什么异常都有可能抛出来,如果我们要调用这样的方法,就需要对他们的异常做一些处理了,我们需要判断什么样的异常需要抛出去,什么样的异常需要封装成RuntimeException。而这些事情就是Throwables类要帮我们做的事情。
假定我们要实现一个doIt的方法,该方法要调用doSomething方法,而doIt的定义中只允许抛出SQLException,我们可以这样做: 1 public void doIt() throwsSQLException { 2 try{ 3 doSomething(); 4 } catch(Throwable throwable) { 5 Throwables.propagateIfInstanceOf(throwable, SQLException.class); 6 Throwables.propagateIfPossible(throwable); 7 } 8 }

请注意doIt的catch块,下面这行代码的意思是如果异常的类型是SQLException,那么抛出这个异常
Throwables.propagateIfInstanceOf(throwable,SQLException.class);
第二行表示如果异常是Error类型,那么抛出这个类型,否则将抛出RuntimeException,我们知道RuntimeException是不需要在throws中声明的。
Throwables.propagateIfPossible(throwable);
Throwables类还为我们提供了一些方便的异常处理帮助方法:
不可变对象有很多优点,包括:
创建对象的不可变拷贝是一项很好的防御性编程技巧。Guava为所有JDK标准集合类型和Guava新集合类型都提供了简单易用的不可变版本。 JDK也提供了Collections.unmodifiableXXX方法把集合包装为不可变形式,但我们认为不够好:
如果你没有修改某个集合的需求,或者希望某个集合保持不变时,把它防御性地拷贝到不可变集合是个很好的实践。
重要提示:所有Guava不可变集合的实现都不接受null值。我们对Google内部的代码库做过详细研究,发现只有5%的情况需要在集合中允许null元素,剩下的95%场景都是遇到null值就快速失败。如果你需要在不可变集合中使用null,请使用JDK中的Collections.unmodifiableXXX方法。更多细节建议请参考“使用和避免null”。
第一种方法使用builder创建: 1 public classImmutableDemo { 2 public static voidmain(String[] args) { 3 Set

第二种方法使用of静态方法创建:
ImmutableSet.of("red","green","black","white","grey");
第三种方法使用copyOf静态方法创建:
ImmutableSet.copyOf(newString[]{"red","green","black","white","grey"});
asList方法是在ImmutableCollection中定义,而所有的不可变集合都会从ImmutableCollection继承,所以所有的不可变集合都会有asList()方法返回当前不可变集合的list视图,这个视图也是不可变的。
不可变集合的使用和普通集合一样,只是不能使用他们的add,remove等修改集合的方法。
Multiset看似是一个Set,但是实质上它不是一个Set,它没有继承Set接口,它继承的是Collection
它本质上是一个Set加一个元素计数器。 1 importcom.google.common.base.Splitter; 2 importcom.google.common.collect.HashMultiset; 3 importcom.google.common.collect.Multiset; 4 5 public classMultisetDemo { 6 public static voidmain(String[] args) { 7 Multiset multiset =HashMultiset.create(); 8 String sentences = "this is a story, there is a good girl in the story."; 9 Iterable

在上面的示例中我们对一段文字拆分成一个一个的单词,然后依次放入到multiset中,注意这段文字中有多个重复的单词,然后我们通过for循环遍历multiset中的每一个元素,并输出他们的计数。输出内容如下:
story:2is:2girl:1there:1a:2good:1the:1in:1this:1
显然计数不是问题,Multiset还提供了add和remove的重载方法,可以在add或这remove的同时指定计数的值。
常用实现 Multiset 接口的类有:
元素被排序存放于TreeMap
看到这里你可能已经发现 Guava Collections 都是以 create 或是 of 这样的静态方法来构造对象。这是因为这些集合类大多有多个参数的私有构造方法,由于参数数目很多,客户代码程序员使用起来就很不方便。而且以这种方式可以返回原类型的子类型对象。另外,对于创建范型对象来讲,这种方式更加简洁。
我们知道Map是一种键值对映射,这个映射是键到值的映射,而BiMap首先也是一种Map,他的特别之处在于,既提供键到值的映射,也提供值到键的映射,所以它是双向Map.
想象这么一个场景,我们需要做一个星期几的中英文表示的相互映射,例如Monday对应的中文表示是星期一,同样星期一对应的英文表示是Monday。这是一个绝好的使用BiMap的场景。 1 mport com.google.common.collect.BiMap; 2 importcom.google.common.collect.HashBiMap; 3 4 public classBiMapDemo { 5 public static voidmain(String[] args) { 6 BiMap

BiMap的值键对的Map可以通过inverse()方法得到。
**BiMap
的常用实现有:**
有时候我们需要这样的数据类型Map
Multimap的实现
Multimap提供了丰富的实现,所以你可以用它来替代程序里的Map
我们通过一个示例来了解Multimap的使用方法:
 1 public classMutliMapTest { 2 public static voidmain(String... args) { 3 Multimap

在guava库中还提供了一种二维表结构:Table。使用Table可以实现二维矩阵的数据结构,可以是稀溜矩阵。
我们看一个使用示例: 1 public classTableDemo { 2 public static voidmain(String[] args) { 3 Table

在上面示例中我们通过HashBasedTable创建了一个行类型为Integer,列类型也为Integer,值为String的Table。然后我们使用put方法向Table中添加了一些值,然后显示这些值
Iterators是Guava中对Iterator迭代器操作的帮助类,这个类提供了很多有用的方法来简化Iterator的操作。

all方法的第一个参数是Iterator,第二个参数是Predicate
 1 Iterator

filter方法的第一个参数是源迭代器,第二个参数是Predicate的实现,其apply方法会返回当前元素是否符合条件。

 1 Iterator

上面的例子中我们将字符串转换成了其长度,transform方法输出的是另外一个Iterator.
不积跬步无以至千里