Guava使用指南基础篇
Guava在很多项目都已经使用过了,最近有点时间,于是重读了下github上的user guidance,然后结合自己的使用经验将常用的一些知识点做一个整理。
怎么使用null
说起null,大家就会想起恶名昭彰的NullPointException. 其实null本身不邪恶,只是很容易混淆,比如一个map中的null代表的究竟是这个key对应的value不存在?还是这个key对应的value本身就是null?
为了避免在代码中反复去检查对象是否为null,Guava提供了Optional工具类,这个类现在已经被JDK8包含了。 但是即使有了Optional,很多人还是误用了,只不过从检查对象是否为null变成了判断Optional对象是否存在(Optional.isPresent()). 这里有一篇文章很好的描述了我们应该如何正确使用Optional。
检查方法调动的前置条件
Guava提供了一个PreConditions类来在方法调用前检查看参数是否合适,比如说,是否为null,是否在某个范围等等。
Preconditions常用方法Object的常用方法
对于Object的常用方法,Guava提供了两大类,一类是用来比较对象是否相等,比如Objects.equal(), Objects.hashcode()以及ComparisonChain, 另一类是toString()的帮助方法, MoreObjects.toStringHelper().
假设我们有如下一个Model类,
public class Model {
private String x;
private int y;
public String getX() {
return x;
}
public void setX(String x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Model model = (Model) o;
if (y != model.y) return false;
return !(x != null ? !x.equals(model.x) : model.x != null);
}
@Override
public int hashCode() {
int result = x != null ? x.hashCode() : 0;
result = 31 * result + y;
return result;
}
}
按照正常的实现方式,可以实现equal()方法和hashCode()方法如上,在equal方法中,可以看到我们需要判断字段x是否非空,那么Guava中提供的Objects.equal()方法实际上就是用来避免字段x可以为null会导致的NullPointException. 使用了Guava的Objects.equal()方法,可以将上面的方法改写为
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Model model = (Model) o;
if (y != model.y) return false;
return Objects.equal(x,model.x);
}
写法上更加简洁。如果你使用的是JDK7以及以上的版本,那么JDK也提供了对应的Objects工具类,可以直接使用。
对应的,hashCode()方法可以改写为
@Override
public int hashCode() {
return Objects.hashCode(x,y);
}
如果equal()方法返回为true,那么两个比较对象的hashCode()方法返回必须相同,如果equal()方法返回false,那么两个比较对象的hashCode()方法返回可以相同也可以不同。
同样,Guava也对实现compareTo()方法做了简化,比如,一般情况下我们实现Model类的compareTo()方法会是:
@Override
public int compareTo(Model o) {
int cmp = this.getX().compareTo(o.getX());
if(cmp!=0)
return cmp;
return Integer.compare(this.getY(),o.getY());
}
如果使用了Guava提供的ComparisonChain, 那么会简化为:
@Override
public int compareTo(Model o) {
return ComparisonChain.start().compare(this.getX(),o.getX()).compare(this.getY(),o.getY()).result();
}
Ordering 排序工具类
Guava提供了Ordering工具类来帮助进行一些通用的排序,可以使得代码更加简单。
怎么创建一个Ordering对象?
创建Ordering对象有两种方式,一种是使用Ordering内嵌的方法来创建,
方法 | 描述 |
---|---|
natural() | 返回的Ordering对象按照自然顺序对元素进行排序,比如整数按照大小,字符串按照字典顺序排序等等。 |
usingToString() | 返回的Ordering对象按照元素进行toString()返回后的结果进行排序 - 按照字符串进行字典排序。 |
另外一种是直接new一个Ordering对象,但是其构造函数需要传入一个Comparator实现。
Ordering<String> usingStringLength = new Ordering<String>(){
public int compare(String left,String right){
return Ints.compare(left.toString().length(),right.toString().length());
}
};
System.out.println(usingStringLength.sortedCopy(Lists.newArrayList("fdd","dfadsfasf","a")));
输出为:
[a, fdd, dfadsfasf]
Ordering链条
对于一个给定的Ordering对象,Ordering对象同样提供了一些方法来结合多种排序,常用的Ordering Chain方法有
方法 | 描述 |
---|---|
reverse() | 返回相反排序的Ordering对象,比如开始假设Ordering对象是按照整数从大到小进行排序的(比如Ordering.natural()),那么Ordering.natural().reverse()就是按照整数从小到大进行排序。 |
nullsFirst() | 返回Ordering对象是按照null值排在非null值前面。 |
onResultOf(Function) | 将传入的Function应用在列表的各个元素上之后, 再使用原始ordering进行排序。 |
compound(Comparator) | compound方法中传入的Comparator对象一般作为第二排序顺序。 |
假设我们有一个Model类,其中有两个属性,x和y,我们想先根据属性x进行排序,然后再根据y进行排序,这个时候我们就可以用到compound(Comparator)方法。
public class Model implements Comparable<Model> {
private String x;
private int y;
public String getX() {
return x;
}
public void setX(String x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
@Override
public int compareTo(Model o) {
return this.getX().compareTo(o.getX());
}
@Override
public String toString() {
return "Model{" +
"x='" + x + '\'' +
", y=" + y +
'}';
}
}
public class Test {
public static void main(String[] args){
Model model1 = new Model();
model1.setX("a");
model1.setY(10);
Model model2 = new Model();
model2.setX("b");
model2.setY(20);
Model model3 = new Model();
model3.setX("b");
model3.setY(11);
ArrayList<Model> models = Lists.newArrayList(model1, model2, model3);
System.out.println(Ordering.natural().sortedCopy(models));
System.out.println(Ordering.natural().compound(new Comparator<Model>() {
@Override
public int compare(Model o1, Model o2) {
return Ints.compare(o1.getY(),o2.getY());
}
}).sortedCopy(models));
}
}
输出为:
[Model{x='a', y=10}, Model{x='b', y=20}, Model{x='b', y=11}]
[Model{x='a', y=10}, Model{x='b', y=11}, Model{x='b', y=20}]
一般使用Ordering Chain方法不超过3个。比如Ordering<Foo> ordering = Ordering.natural().nullsFirst().onResultOf(sortKeyFunction); 对于Ordering Chain方法调用, 还有一个backward rule, 就是要对于Ordering Chain的方法调用,是从最右边开始执行到最左边。因为Ordering Chain的实现是每个Ordering Chain调用会wrap前一个Ordering Chain调用来生成新的一个Ordering对象,所以最右边的Ordering Chain调用会被先执行。