Guava使用指南基础篇

2018-07-26  本文已影响76人  可文分身

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常用方法

图片来自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调用会被先执行。

上一篇下一篇

猜你喜欢

热点阅读