Comparison method violates its general contract
今天在做List中Object排序时,报错:
Comparison method violates its general contract
我的方法是 使pojo实现Comparable接口,重写compareTo方法.
最原始的写法为:
@Override public int compareTo(Object o) { if(!(o instanceof TopicReportDto)){ new RuntimeException("比较类型不匹配"); } TopicReportDto other = (TopicReportDto) o; if(other.getViews() == null || this.getViews() == null){ return -1; }
if(other.getViews() > this.getViews()){ return 1; }else if(other.getViews() < this.getViews()){ return -1; }else{ return 0; } }
这种写法在JDK1.6运行并没有什么问题,但是在JDK1.7+运行就存在问题.
参考这两篇文章:
http://blog.csdn.net/ghsau/article/details/42012365
http://iamyida.iteye.com/blog/2255804
解决方法有两种:
1.JVM中添加参数 : -Djava.util.Arrays.useLegacyMergeSort=true
2.修改代码 : 修改compareTo 方法
为了避免项目部署到没没有设置JVM参数的机器上再次报错的情况出现,我选择修改代码.
修改代码的过程中,我尝试了很多方法,但是都没有成功.
在iteye哥们中有一句话提醒了我:
因为他写的代码里没有考虑对象o1和对象o2为Null的情况,即当o1与o2都为null时两者大小如何判定呢,当o1为null但o2不为null时两者大小又如何判定了呢,
同理当o2为null但o1不为null时两者大小又如何判定呢又不得而知,或许你又会说,我这两个对象不可能为null,但那是你认为,
JVM不知道,它只要求你的逻辑必须严谨,严格考虑各种情况下两者大小的判定原则。
仔细阅读后豁然开朗,原来是在compareTo方法中还需要考虑到 各种 传入值为空的返回情况
在我上面的代码中只考虑到,两者其中一个为空值的情况,还存在 两者 都为空值的情况.
看来在新的JDK中,以后在做compareTo方法时,要注意:
1.各种为空值的情况
2.大于
3.小于
4.等于
修改后的代码:
@Override public int compareTo(Object o) { if(!(o instanceof TopicReportDto)){ new RuntimeException("比较类型不匹配"); } TopicReportDto other = (TopicReportDto) o; //判断传入值为空值情况 if(other.getViews() == null && this.getViews() == null){ return 0; } if(other.getViews() == null){ return -1; } if(this.getViews() == null){ return 1; } //如果不为空值,比较传入的值 // return other.getViews().compareTo(this.getViews()); if(other.getViews() > this.getViews()){ return 1; }else if(other.getViews() < this.getViews()){ return -1; }else{ return 0; } }