本章把剩下的部分一笔带过,主要集中讲Guava还提供哪些功能,有个大概认知,具体使用,看文末附上的官方javadoc文档。

本来优先学习Guava的目的是工作中实在是太多地方需要工具类的帮助,所以希望能先了解Guava都支持哪些功能,避免重复造轮子。 但是现在发现,除了集合工具类以外,Guava提供的其他工具类用到不多,有些还有点鸡肋,因此,为避免浪费宝贵的业余时间,开始加快速度,集中阐述Guava工具包里都有哪些功能,不再赘述细节。

并发

JDK从5开始提供的并发包其实已经很强大了。尤其是executor系列。 Guava做了一些补充,尤其是在异步化方面。 下面是一些Guava给到的额外的补充: - ListenableFuture:针对原始的executor可能返回的Future,Guava提供的新类型。原来的Future可以获取异步任务返回的结果,但是如果异步任务还没算出结果,那么线程就要等待,等异步任务算出结果再得到结果。而Guava这个就灵活了,你还可以给它注册个监听器,如果结果算好了,自动回调你注册的方法来处理结果。 - FutureCallback:这个也很棒,除了注册监听器以外,你还可以注册这个回调,这个回调接口有两个方法,onSuccess(V)onFailure(Throwable),把成功失败分开来处理,更加好用。 - ListeningExecutorService:问题来了,普通的Future可是JDK默认的Executor返回的,怎么得到Guava的新类型呢?用MoreExecutors.listeningDecorator(ExecutorService)方法包装一下默认的,这样得到的就是ListenableFuture啦 - CheckedFuture<V, X extends Exception>:这个是ListenableFuture的一个子接口,有时候我们的异步操作会抛出受检异常,那么我们就需要返回这个Future,可以使用Futures.makeChecked(ListenableFuture<V>, Function<Exception, X>)来吧普通的ListenableFuture变成CheckedFure - Service:Guava提供了一个高层接口,这个接口代表某一项业务,它有自己的状态,NEW->STARTING->RUNNING->STOPPING->TERMINATED以及FAILED等,用诸如startAsync()或者stopAsync()这样的方法就能启动或者停止service,当然不同的实现还有其他几种状态的流转方法。另外,你还可以注册监听器,当状态改变的事件发生时,告知监听器,执行相应的逻辑。你还可以让service同步地执行,调用awaitRunning()即可。Service的接口实现众多,下面列举如下: - AbstractIdleService:这个service在执行的时候不做逻辑,只有启动和停止的时候做逻辑。 - AbstractExecutionThreadService:这个service会开启一个单线程来做逻辑,有startup、run、triggerShutdown三处地方可以做逻辑。 - AbstractScheduledService:看名字就知道了,这是周期性的service,可以周期性的运行。 - AbstractService:这是纯粹的抽象类,用来给你自己实现属于自己的service的 - ServiceManager:如果你有很多servcie要管理,可以使用这个ServiceManager来集中管理,比如一下子全部运行,一下子全部停止等。

字符串

Guava提供了很多好用的字符串工具类: - Joiner:这个很好懂吧,看名字就知道是字符串拼接的。例子如下:

Joiner joiner = Joiner.on("; ").skipNulls();
return joiner.join("Harry", null, "Ron", "Hermione");

注意这个类是不可变的,每一次修改都会生成新的类,所以链式调用时小心点儿。不过好处也是有的,可以声明成静态变量,然后给多线程共用。 - Splitter:有拼接就有拆分,这个用来方便地拆分,不会引起歧义。话说我才知道JDK的原生方法String.split原来可以这么坑,比如: ",a,,b,".split(",")拆分后的结果是什么? 我一直以为是"", "a", "", "b", "",结果却被告知是"", "a", "", "b",因为末尾的空字符串会被省略掉,卧槽,以前都不知道。 使用Guava版本的就不会有这种歧义,因为你在创建Splitter的时候,可以指定行为。 - CharMatcher:这个有点儿类似于Predicate,实际上它就是实现的Predicate<Character>,主要是用来处理字符串的,做一些断言,过滤,转换的操作,例子如下:

String noControl = CharMatcher.javaIsoControl().removeFrom(string); // remove control characters
String theDigits = CharMatcher.digit().retainFrom(string); // only the digits
String spaced = CharMatcher.whitespace().trimAndCollapseFrom(string, ' ');
  // trim whitespace at ends, and replace/collapse whitespace into single spaces
String noDigits = CharMatcher.javaDigit().replaceFrom(string, "*"); // star out all digits
String lowerAndDigit = CharMatcher.javaDigit().or(CharMatcher.javaLowerCase()).retainFrom(string);
  // eliminate all characters that aren't digits or lowercase

注意,这个方法不认识Unicode编码,只认识char,所以不要妄想它能很好地处理中文。中文在它眼里就是多个字符的char。 - Charsets:这个不重要,就是让你使用这个来替代直接使用字符串"UTF-8"来声明字符集类型,如果是JDK7,已经有官方的实现了,可以使用StandardCharsets - CaseFormat:转换一些大小写或者格式,比如驼峰命名法的转换:

CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.LOWER_CAMEL, "CONSTANT_NAME")); // returns "constantName"

在编程的时候,尤其是框架编程者,感觉还是蛮有用的

基本类型工具包

本来还有个拼internetDomainName的工具类,实现感觉鸡肋,就不介绍了。 这一节其实也没什么好介绍的,前面有提到过,Guava几乎为所有的类型都提供了工具类,只要在类型名字后面加个s就行了。 比如你想看String这个类有什么好用的方法,直接敲Strings就行了。同样地,基本类型int,敲Ints,byte就敲Bytes。以此类推。 还贴心地提供了无符号的基本类型,比如:UnsignedInts、UnsignedLongs等。

开闭区间

提供一个叫做Range的类来实现开闭区间。 用法如下:

Range.closed(1, 3).contains(2); // returns true
Range.closed(1, 3).contains(4); // returns false
Range.lessThan(5).contains(5); // returns false
Range.closed(1, 4).containsAll(Ints.asList(1, 2, 3)); // returns true

其他的用法就不赘述了

IO工具类

IO操作基本上分两种,一种是字节型的,一种是字符型的。 于是Guava给出了两种工具类。ByteStreams用来搞定字节型,比如InputStream或者OutputStream。而CharStreams用来搞定字符型,比如Reader或者Writer。 注意这两个工具类不负责打开流和关闭流,只负责提供便利的方法,比如我曾经就使用到一个很方便的方法:long copy(InputStream, OutputStream),真爽啊,把一个流的内容直接搞到另一个流里去。