guava 常用对象方法

时间:2022-06-25 20:47:24

介绍下guava提供的一些便利的针对对象的操作,这些操作提高了代码的简洁性和可读性

equals

现在有个User类如下所示

class User{

private int age;
private String name;
private Date birthday;
...省略get/set
}

如果要重写这个类的equals方法,通常会这样做

    public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
User user = (User) o;
if (age != user.age) return false;
if (name != null ? !name.equals(user.name) : user.name != null) return false;
return !(birthday != null ? !birthday.equals(user.birthday) : user.birthday != null);
}

可以看出针对引用类型的namebirthday。都要比较一下null的情况。代码有些啰嗦,不够简洁
name != null ? !name.equals(user.name) : user.name != null

针对这个情况,guava提供了Objects.equal(Object,Object)方法,使用guava后的写法如下:

    public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
User user = (User) o;
return age == user.age &&
Objects.equal(name, user.name) && //使用Objects.equal
Objects.equal(birthday, user.birthday);
}

可以看到使用Objects.equal方法增加代码的可读性和简洁性 。其实Objects.equal方法内部也是走的同样的判断逻辑,源码如下:

  public static boolean equal(@Nullable Object a, @Nullable Object b) {
return a == b || (a != null && a.equals(b));
}

hashcode

还是用先前的User类,如果要重写hashCode方法,通常做法如下:

    public int hashCode() {
int result = age;
result = 31 * result + (name != null ? name.hashCode() : 0);
result = 31 * result + (birthday != null ? birthday.hashCode() : 0);
return result;
}

如果用guava,就是这样的:

    @Override
public int hashCode() {
return Objects.hashCode(age, name, birthday);
}

guava的Objects.hashCode也会迭代传入的参数计算hash值,源码如下:

    public static int hashCode(Object a[]) {
if (a == null) return 0;
int result = 1;
for (Object element : a) //循环参数,计算hash
result = 31 * result + (element == null ? 0 : element.hashCode());
return result;
}

toString

重写对象的toString方法,在代码调试和日志记录的非常有用,重写UsertoString通常做法如下:

    public String toString() {
final StringBuffer sb = new StringBuffer("User{");
sb.append("age=").append(age);
sb.append(", name='").append(name).append('\'');
sb.append(", birthday=").append(birthday);
sb.append('}');
return sb.toString();
}

看起来这一坨代码就乱,如果要去掉某个属性,也不好找。如果用guava就如下所示:

    public String toString() {
return MoreObjects.toStringHelper(this)
.add("age", age) //如果要去掉某个敏感的属性,直接删掉就可以了
.add("name", name)
.add("birthday", birthday)
.toString();
}

compare/compareTo

如果User实现了Comparable接口需要重写compareTo方法,通常写法如下:

    public int compareTo(User o) {
int cmp = (age < o.age) ? -1 : ((age > o.age) ? 1 : 0);
if (cmp != 0) {
return cmp;
}
cmp = birthday.compareTo(o.birthday);
if (cmp != 0) {
return cmp;
}
return name.compareTo(o.name);
}

出现错误也比较难定位,如果用guava,写法如下:

public int compareTo(User o) {
return ComparisonChain.start()
.compare(age, o.age)
.compare(birthday, o.birthday)
.compare(name, o.name)
.result();
}

ComparisonChain提供者中链式的编程风格,虽然这些属性的比较代码是连起来写的。但是是有“短路”规则的即:如果有一个compare操作返回值为非零,就不会执行后面的属性比较了。

默认值

有时候会遇到这样的逻辑:如果第一个值为null,就取默认值,否则就去第一个值。

String ret=serivce.operation();
return ret!=null?ret:"默认值";

在guava中可以用MoreObjects.firstNonNull(first,second)方法

String ret=serivce.operation();
return MoreObjects.firstNonNull(ret,"默认值");//使用MoreObjects.firstNonNull

不过MoreObjects.firstNonNull(first,second)中如果first和second都为null的时候就会抛出NPE(NullPointerException)异常

IDE的支持

IDE对这些也都有支持,以idea为例,可以选择guava的实现

  1. 按快捷键Alt+Insert
    guava 常用对象方法

  2. 选择guava的实现
    guava 常用对象方法

参照:
1、《getting started with google guava》
2、https://github.com/google/guava/wiki/CommonObjectUtilitiesExplained