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

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

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,919评论 6 502
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,567评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,316评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,294评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,318评论 6 390
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,245评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,120评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,964评论 0 275
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,376评论 1 313
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,592评论 2 333
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,764评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,460评论 5 344
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,070评论 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,697评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,846评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,819评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,665评论 2 354

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,654评论 18 139
  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,625评论 18 399
  • 四月,你来了。初次见面你不认识我,我也不认识你。我们彼此都没说过一句话,只是在饭桌上看了对方一眼。同样的我们只...
    路人皆知我是陌生人阅读 380评论 3 1
  • 最美不过人间四月天!春风十里,不如你! 每个人都有一个小小的港湾,那是一个安放温情的地方。每当安静...
    晓枫Joyce阅读 832评论 0 0
  • 鹧鸪天 寸寸肝肠唱旧音,千番滋味到如今。十年衫袖穿桃粉,一夜宫商见逸淫。 罗帐暖,玉楼深。兽香添醉意沉沉。青山向我...
    何其微在山之阿阅读 190评论 1 1