Guava是一种基于开源的Java库,其中包含谷歌正在由他们很多项目使用的很多核心库。这个库是为了方便编码,并减少编码错误。这个库提供用于集合,缓存,支持原语,并发性,常见注解,字符串处理,I/O和验证的实用方法。
字符串strings
Joiner
将字符串根据分隔符拆分连接,如果单用Java实现可能要判断为null的情况,代码会有好几行,代码本省不复杂,使用Guava提供的流式风格Joiner,代码看起来精简了很多
String result = Joiner.on(";").skipNulls().join(Arrays.asList("a", "b",null));
比如也可以将null替换为某个字符串
String result = Joiner.on(";").useForNull("hell").join(Arrays.asList("a",null, "b",null));
Splitter
与Java中String 的split相似,但是提供更加丰富的功能,使用String中的split需要判断空格等情况,看Guava中实现
Splitter.on(";").trimResults().omitEmptyStrings().split("java; ;;db");
上面代码返回[ java, db]
主要方法:
| 方法 | 描述 | 示例 |
|---|---|---|
| Splitter.on(char) | 使用单独的一个字符分隔指定序列 | Splitter.on(‘;’) |
| Splitter.on(CharMatcher) | 使用某类的字符分隔指定序列 | Splitter.on(CharMatcher.BREAKING_WHITE) Splitter.on(CharMatcher.anyOf(“;,.”)) |
| Splitter.on(String) | 使用字符串分隔指定序列 | Splitter.on(“, “) |
| Splitter.on(Pattern) Splitter.onPattern(String) | 根据正则表达式分隔指定序列 | Splitter.onPattern(“\r?\n”) |
| Splitter.fixedLength(int) | 将指定序列分隔成指定长度的子串,最后一个子串可能小于指定的值,但永远不可能为空 | Splitter.fixedLength(3) |
还有一些其他方法,如忽略空字符串,剔除空字符、剔除指定字符等
CharMatcher
可以把CharMatcher直观的想象成是一个表示字符的特殊类,像数字或空格之类。实际上,CharMatcher就是一个字符的布尔判判断 — 它实现了Predicate<Character>接口,因为它太常用了,例如:所有空格,所有小写字母等,Guava才为字符提供了这个API。
CharMatcher的作用就是在一个字符序列上执行一系列的操作:裁剪,折叠,移除,保留等等。一个CharMatcher类型的对象表示:
- 一个“匹配”的字符由什么组成? 有很多操作来回答这个问题。
- 对这些“匹配”的字符要做什么?
CharMatcher digit = CharMatcher.digit();
boolean isDigit = digit.matchesAnyOf("ssd"); //false
isDigit = digit.matchesAnyOf("111d") //true
isDigit = digit.matchesAllOf("111") //true
isDigit = digit.matchesAllOf("111d") //false
常用方法
| 方法 | 描述 |
|---|---|
| anyOf(CharSequence) | 包括想要匹配的所有字符。例如CharMatcher.anyOf("aeiou")匹配所有小写的元音字符 |
| is(char) | 匹配指定的字符 |
| inRange(char, char) | 匹配一个范围内的字符,例如CharMatcher.inRange('a', 'z') |
更多方法参考doc文档
Charsets
定义一些常量,比如
public static final Charset ISO_8859_1 = Charset.forName("ISO-8859-1"); public static final Charset UTF_8 = Charset.forName("UTF-8"); public static final Charset UTF_16BE = Charset.forName("UTF-16BE");
防止我们在程序内部写成固定值
String s = new String("hello".getBytes(),"UTF-8");
//应该这样写
s = new String("hello".getBytes(),Charsets.UTF_8);
如果使用JDK>1.6 可以使用StandardCharsets中的常量!
预检查Preconditions
程序中的检查经常用到,比如检查一个对象是否为空等,Guava提供了各种静态检查方法,每个方法有三个不同的变体
- 无参的方法。 如果有异常会直接抛出,不会有任何错误信息
- 有一个Object参数的方法。
如果有异常会直接抛出,使用
Object.toString()作为错误信息 - 一个String和一个可变的Object参数 只接受%s占位符
checkArgument(i < j, "Expected i < j, but %s > %s", i, j);
常用方法
| 签名 | 描述 | 失败时抛出异常 |
|---|---|---|
| checkArgument(boolean) | 检查boolean是否为true,用于验证参数 | IllegalArgumentException |
| checkNotNull(T) | 检查参数是否为null,直接返回该参数,可以内联使用 | NullPointerException |
| checkState(boolean) | 检查Object的状态,不依赖于方法参数,例如检查Iterator是否在remove之前调用了next | IllegalStateException |
| checkElementIndex(int index, int size) | 检查index的索引处的元素是否在List/Array/String内,元素的索引从0(包括)到size(不包括),不需要直接传List/Array/String,传他们的长度即可,返回index |
IndexOutOfBoundsException |
| checkPositionIndex(int index, int size) | 检查index是否是一个合法的位置索引,范围从0(包括)到size(包括),不需要直接传List/Array/String,传他们的长度即可,返回index |
IndexOutOfBoundsException |
| checkPositionIndexes(int start, int end, int size) | 检查[start, end)的范围是否是List/Array/String的子集 | IndexOutOfBoundsException |
缓存cache
Java中使用Map做缓存最大的缺点是我们无法控制内存占用大小,或者基于LinkedHashMap实现LRU算法,Guava考虑到了这点,提供了多种缓存回收策略,防止内存溢出,个人觉得这个很使用
- 基于内存占用大小的回收
如果不希望缓存占用过大的内存空间,查看CacheBuilder.maximumSize(long)。最近最久未使用的key-value将被回收。注意:Cache可能在尚未达到此限制的时候就进行回收了,尤其当大小接近限制的时候。
- 基于时间回收
Guava提供了两种基于时间的回收方式:
expireAfterAccess(long, TimeUnit),仅在最后一次读写访问之后在指定的时间后才会回收,回收顺序类似于基于大小的回收。
expireAfterWrite(long, TimeUnit),在key-value被创建、修改后经过指定的时间后被回收,这对于一段时间后缓存的数据已经无效的情况下非常有用。
Object方法
常用方法
- equal
如果一个对象的属性可能为null,实现Object.equals()就有点麻烦了,因为要单独的检查null的情况。使用Objects.equal()可以在可能为null的情况下执行equals判断而不抛出NullPointerException。
jects.equal("ac", "ac"); //true
Objects.equal(null, "ac"); //false
Objects.equal("ac", null); //false
Objects.equal(null, null); //true
- compare/compareTo
直接实现Comparator或Comparable方法,在属性很多时,看起来很乱
Guava提供了ComparisonChain。
ComparisonChain是惰性比较:它仅在找到非零值的时候才进行比较,完成后忽略后面的输入
blic int compareTo(Hello that) {
return ComparisonChain.start()
.compare(this.aString, that.aString)
.compare(this.name, that.name)
.compare(this.anEnum, that.anEnum, Ordering.nature().nullsFirst())
.result();
}
这样流式的方式具有更好的可读性,不会导致意外的错误,除了必须的不会做任何额外的工作,足够精简
异步编程ListeningExecutorService
Java中通过返回Future实现异步编程,类似
static final ExecutorService executorService = new ThreadPoolExecutor(10,20,1000, TimeUnit.SECONDS,new LinkedBlockingDeque<>(100));
public static void main(String[] args) throws ExecutionException, InterruptedException {
Future<String> future = executorService.submit(new Run());
String result = future.get();
System.out.println(result);
}
static class Run implements Callable<String>{
@Override
public String call() throws Exception {
//do anything
return "success";
}
}
但是future.get()还是阻塞的,所以还不算真正意义上的异步,Guava提供了ListeningExecutorService对 ExecutorService进行了包装,通过回调函数的方式,实现真正异步,即在方法执行完成后执行绑定的回调的函数,执行回调函数时任务之间不需要等待
static final ExecutorService executorService = new ThreadPoolExecutor(10,20,1000, TimeUnit.SECONDS,new LinkedBlockingDeque<>(100));
static final ExecutorService callbackExecutor = Executors.newSingleThreadExecutor();
static ListeningExecutorService listeningExecutorService;
public static void main(String[] args) throws ExecutionException, InterruptedException {
listeningExecutorService = MoreExecutors.listeningDecorator(executorService);
ListenableFuture<String> listenableFuture = listeningExecutorService.submit(new Run());
Futures.addCallback(listenableFuture, new FutureCallback<String>() {
@Override
public void onSuccess(@Nullable String result) {
System.out.println(result);
}
@Override
public void onFailure(Throwable t) {
}
},callbackExecutor);
}
static class Run implements Callable<String>{
@Override
public String call() throws Exception {
//do anything
return "success";
}
}