美文网首页
Guava使用指南基础篇

Guava使用指南基础篇

作者: 可文分身 | 来源:发表于2018-07-26 10:03 被阅读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调用会被先执行。

    相关文章

      网友评论

          本文标题:Guava使用指南基础篇

          本文链接:https://www.haomeiwen.com/subject/loavuftx.html