什么是Guava
Guava工程包含了若干被Google的 Java项目广泛依赖 的核心库,例如:集合 [collections] 、缓存 [caching] 、原生类型支持 [primitives support] 、并发库 [concurrency libraries] 、通用注解 [common annotations] 、字符串处理 [string processing] 、I/O 等等。 所有这些工具每天都在被Google的工程师应用在产品服务中。
用Google Guava进行Java开发
自己所在公司项目大量使用Guava类库,且涉及的知识点较多,故参考网上资料进行了学习实践。
1.1-使用和避免null
轻率地使用null可能会导致很多令人惊愕的问题。通过学习Google底层代码库,我们发现95%的集合类不接受null值作为元素。我们认为, 相比默默地接受null,使用快速失败操作拒绝null值对开发者更有帮助。鉴于这些原因,很多Guava工具类对Null值都采用快速失败操作,除非工具类本身提供了针对Null值的因变措施。此外,Guava还提供了很多工具类,让你更方便地用特定值替换Null值。
Optional
大多数情况下,开发人员使用null表明的是某种缺失情形:可能是已经有一个默认值,或没有值,或找不到值。例如,Map.get返回null就表示找不到给定键对应的值。
Guava用Optional<T>表示可能为null的T类型引用。一个Optional实例可能包含非null的引用(我们称之为引用存在),也可能什么也不包括(称之为引用缺失)。它从不说包含的是null值,而是用存在或缺失来表示。但Optional从不会包含null值引用。
package cn.jyycode.guava.chapter1;
/**
* Optional http://ifeve.com/google-guava-using-and-avoiding-null/
*
* @author zhangjiayuan@qipeipu.com
* @date 2019/1/11 11:36
* @since 1.0.0
*/
//注意这里应用Google的Optional类
import com.google.common.base.Objects;
import com.google.common.base.Optional;
/**
* Guava用Optional<T>表示可能为null的T类型引用。
* 一个Optional实例可能包含非null的引用(我们称之为引用存在),
* 也可能什么也不包括(称之为引用缺失)。它从不说包含的是null值,
* 而是用存在或缺失来表示。但Optional从不会包含null值引用。
*/
public class Main1 {
public static void main(String[] args) {
Optional<Integer> possible = Optional.of(5);
boolean result1 = possible.isPresent();
int result2 = possible.get();
Optional<Integer> possible1 = Optional.fromNullable(null);
int result3 = possible1.or(2);
possible1.orNull();
possible1.asSet();
System.out.println(result1 + "===" + result2 + "===" + result3);
//默认值替换可能的null值
Objects.firstNonNull(1, 1);
}
}
运行结果:
1.2-前置条件
Guava在Preconditions类中提供了若干前置条件判断的实用方法
方法声明(不包括额外参数) | 描述 | 检查失败时抛出的异常 |
checkArgument(boolean) | 检查boolean是否为true,用来检查传递给方法的参数。 | IllegalArgumentException |
checkNotNull(T) | 检查value是否为null,该方法直接返回value,因此可以内嵌使用checkNotNull。 | NullPointerException |
checkState(boolean) | 用来检查对象的某些状态。 | IllegalStateException |
checkElementIndex(int index, int size) | 检查index作为索引值对某个列表、字符串或数组是否有效。index>=0 && index<size * | IndexOutOfBoundsException |
checkPositionIndex(int index, int size) | 检查index作为位置值对某个列表、字符串或数组是否有效。index>=0 && index<=size * | IndexOutOfBoundsException |
checkPositionIndexes(int start, int end, int size) | 检查[start, end]表示的位置范围对某个列表、字符串或数组是否有效* | IndexOutOfBoundsException |
package cn.jyycode.guava.chapter1;
import com.google.common.base.Preconditions;
import org.junit.jupiter.api.Test;
/**
* Preconditions 前置条件:让方法调用的前置条件判断更简单。
* http://ifeve.com/google-guava-preconditions/
*
* @author zhangjiayuan@qipeipu.com
* @date 2019/1/11 14:26
* @since 1.0.0
*/
public class Main2 {
@Test
public static void main(String[] args) {
Preconditions.checkArgument(2 > 1, "121");
Preconditions.checkNotNull(new Integer(5));
Preconditions.checkNotNull(null);
// Preconditions.checkNotNull(null);
Preconditions.checkElementIndex(3, 3);
Preconditions.checkPositionIndex(2, 3);
}
}
运行结果:
1.3-常见Object方法
equals
当一个对象中的字段可以为null时,实现Object.equals方法会很痛苦,因为不得不分别对它们进行null检查。使用Objects.equal帮助你执行null敏感的equals判断,从而避免抛出NullPointerException
hashCode
用对象的所有字段作散列[hash]运算应当更简单。Guava的Objects.hashCode(Object...)会对传入的字段序列计算出合理的、顺序敏感的散列值。你可以使用Objects.hashCode(field1, field2, …, fieldn)来代替手动计算散列值。
注意:JDK7引入的Objects类提供了一样的方法Objects.hash(Object...)
toString
好的toString方法在调试时是无价之宝,但是编写toString方法有时候却很痛苦。使用 Objects.toStringHelper可以轻松编写有用的toString方法
compare/compareTo
实现一个比较器[Comparator],或者直接实现Comparable接口有时也伤不起
package cn.jyycode.guava.chapter1;
import com.google.common.base.Objects;
import com.google.common.collect.ComparisonChain;
/** Objects
* 执行null敏感的equals判断,从而避免抛出NullPointerException
* @author zhangjiayuan@qipeipu.com
* @date 2019/1/11 14:40
* @since 1.0.0
*/
public class Main3 implements Comparable<Main3> {
private String firstName;
private String lastName;
//ComparisonChain执行一种懒比较:它执行比较操作直至发现非零的结果,
// 在那之后的比较输入将被忽略。
@Override
public int compareTo(Main3 that) {
return ComparisonChain.start()
.compare(this.firstName,that.lastName)
.compare(this.lastName,that.lastName)
.result();
}
public static void main(String[] args) {
boolean result1 = Objects.equal("a","a");
boolean result2 = Objects.equal(null,"a");
boolean result3 = Objects.equal("a",null);
boolean result4 = Objects.equal(null,null);
System.out.println(result1+"=="+result2+"=="+result3+"=="+result4);
String result5 = Objects.toStringHelper("Main3").add("x",1).toString();
System.out.println(result5);
}
}
运行结果:
1.4-Guava强大的”流畅风格比较器”
排序器[Ordering]是Guava流畅风格比较器[Comparator]的实现,它可以用来为构建复杂的比较器,以完成集合排序的功能。
从实现上说,Ordering实例就是一个特殊的Comparator实例。Ordering把很多基于Comparator的静态方法(如Collections.max)包装为自己的实例方法(非静态方法),并且提供了链式调用方法,来定制和增强现有的比较器
package cn.jyycode.guava.chapter1;
import com.google.common.collect.Ordering;
import com.google.common.primitives.Ints;
/**
* @author zhangjiayuan@qipeipu.com
* @date 2019/1/11 14:57
* @since 1.0.0
*/
public class Main4 {
private static String left = "abc";
private static String right = "def";
public static void main(String[] args) {
Ordering.natural();
Ordering.usingToString();
//Ordering.from();
Ints.compare(left.length(),right.length());
/* 当阅读链式调用产生的排序器时,应该从后往前读。上面的例子中,排序器首先调用apply方法获
取sortedBy值,并把sortedBy为null的元素都放到最前面,然后把剩下的元素按sortedBy进行
自然排序。之所以要从后往前读,是因为每次链式调用都是用后面的方法包装了前面的排序器。
Ordering<Foo> ordering = Ordering.natural().nullsFirst().onResultOf(new
Function<Foo, String>() {
public String apply(Foo foo) {
return foo.sortedBy;
}
});*/
}
}
1.5-Throwables:简化异常和错误的传播与检查
异常传播
有时候,你会想把捕获到的异常再次抛出。这种情况通常发生在Error或RuntimeException被捕获的时候,你没想捕获它们,但是声明捕获Throwable和Exception的时候,也包括了了Error或RuntimeException。Guava提供了若干方法,来判断异常类型并且重新传播异常。
hrowables.propagate(t);—— 这样可以向编译器声明这里一定会抛出异常
package cn.jyycode.guava.chapter1;
import com.google.common.base.Throwables;
/**
* Throwables.propagate异常传播
* 在java7以上没必要
*
* @author zhangjiayuan@qipeipu.com
* @date 2019/1/11 15:09
* @since 1.0.0
*/
public class Main5 {
public static void main(String[] args) throws Exception {
try {
} catch (Exception | Error e) {
Throwables.propagateIfPossible(e, Exception.class);
throw Throwables.propagate(e);
}
}
}