本文记录的是2016年4月初发生的事情。
前几天,标准CI的静态检查页面发现一个项目组同事引入的FindBugs问题,EQ_COMPARETO_USE_OBJECT_EQUALS
,CI对这个问题给出的介绍如下
Class defines compareTo(...) and uses Object.equals()
同事没见过这个问题,不了解如何修改,于是在中午回基地吃饭的路上一起讨论这个问题。
其实这个问题并不复杂,也不困难。FindBugs工具是在抱怨一个Java Bean类实现了Comparable
接口,但却使用了父类(java.lang.Object
类)的equals
方法,没有覆盖父类的实现,违反了接口的使用规则。
因此消除EQ_COMPARETO_USE_OBJECT_EQUALS
的方法:
-
在这个Java Bean类中覆盖父类的
equals
方法; -
对于Java Bean类的两个对象x和y,
equals
方法的实现保证如下等式成立x.compareTo(y) == 0时,x.equals(y)为true
修改方法很简单,本项目使用了Lombok,因此为Java Bean类实现equals
方法并不需要写代码。同时Lombok还很贴心的生成了hashCode
方法,这又避免了另外一个FindBugs问题,即实现equals
方法时,需要同步实现hashCode
方法。
问题按时解决了,成功避免项目组被部门通报、晾晒。那么接下来需要复习一下功课,避免后续掉到相同的坑里。如下是相关的资料,作为对上述修改方法的补充说明,蛮好理解的,所以就不费神转换了。
EQ_COMPARETO_USE_OBJECT_EQUALS
的官方定义
如下截取自FindBugs官方文档
This class defines a compareTo(...) method but inherits its equals() method from java.lang.Object.
Generally, the value of compareTo should return zero if and only if equals returns true.
If this is violated, weird and unpredictable failures will occur in classes such as PriorityQueue.
In Java 5 the PriorityQueue.remove method uses the compareTo method, while in Java 6 it uses the equals method.From the JavaDoc for the compareTo method in the Comparable interface:
It is strongly recommended, but not strictly required that (x.compareTo(y)==0) == (x.equals(y)).
Generally speaking, any class that implements the Comparable interface and violates this condition should clearly indicate this fact.
The recommended language is "Note: this class has a natural ordering that is inconsistent with equals."
Comparable
的官方文档
如下截取自Java官方文档。
public interface Comparable
This interface imposes a total ordering on the objects of each class that implements it. This ordering is referred to as the class's natural ordering, and the class's compareTo method is referred to as its natural comparison method.
Lists (and arrays) of objects that implement this interface can be sorted automatically by Collections.sort (and Arrays.sort). Objects that implement this interface can be used as keys in a sorted map or as elements in a sorted set, without the need to specify a comparator.
The natural ordering for a class C is said to be consistent with equals if and only if e1.compareTo(e2) == 0 has the same boolean value as e1.equals(e2) for every e1 and e2 of class C. Note that null is not an instance of any class, and e.compareTo(null) should throw a NullPointerException even though e.equals(null) returns false.
It is strongly recommended (though not required) that natural orderings be consistent with equals. This is so because sorted sets (and sorted maps) without explicit comparators behave "strangely" when they are used with elements (or keys) whose natural ordering is inconsistent with equals. In particular, such a sorted set (or sorted map) violates the general contract for set (or map), which is defined in terms of the equals method.For example, if one adds two keys a and b such that (!a.equals(b) && a.compareTo(b) == 0) to a sorted set that does not use an explicit comparator, the second add operation returns false (and the size of the sorted set does not increase) because a and b are equivalent from the sorted set's perspective.
Virtually all Java core classes that implement Comparable have natural orderings that are consistent with equals. One exception is java.math.BigDecimal, whose natural ordering equates BigDecimal objects with equal values and different precisions (such as 4.0 and 4.00).
For the mathematically inclined, the relation that defines the natural ordering on a given class C is:
{(x, y) such that x.compareTo(y) <= 0}.
The quotient for this total order is:
{(x, y) such that x.compareTo(y) == 0}.
It follows immediately from the contract for compareTo that the quotient is an equivalence relation on C, and that the natural ordering is a total order on C. When we say that a class's natural ordering is consistent with equals, we mean that the quotient for the natural ordering is the equivalence relation defined by the class's equals(Object) method:{(x, y) such that x.equals(y)}.
This interface is a member of the Java Collections Framework.
高等代数 or 离散数学
看过上面截取的材料,突然发现接口Comparable
的compareTo
方法满足如下要求:
- 自反,即
x.compareTo(x) == 0
; - 对称,即
x.compareTo(y) == 0
,同时y.compareTo(x) == 0
; - 传递,如果
x.compareTo(y) == 0
并且y.compareTo(z) == 0
,那么一定有x.compareTo(z) == 0
;
不由得赞叹老外写文档时的确是相当的用心,值得学习。另外更加觉得当年读数学系的信息与计算科学专业是正确的选择。