Java 记一次自定义比较器中compareTo方法使用long强转int作为比较结果产生的bug
时间:2022-07-22
本文章向大家介绍Java 记一次自定义比较器中compareTo方法使用long强转int作为比较结果产生的bug,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
最近换了新工作,改bug作为熟悉业务及代码的快速途径,是每个新人都要经历的
代码不难,难的是业务不熟,很多地方不知道为什么要这么写。当然,时间久了就好了
这次要找的bug是排序问题,前端请求接口,按某个字段排序后,返回的结果总是很怪异,数据最多的那个总是与排序要求相反。
比如升序排序,他会跑到最后一页的最后一条
降序排序会跑到第一条
捋代码发现他的排序逻辑如下:
请求参数:orderBy=validCount&sortType=desc¤tPage=1
//controller封装参数调用service的查询
//service查询出全部,进行排序后,根据分页参数进行逻辑分页
Collections.sort(listIntelSourceListVos);
return new Pager<>(currentPage, pageSize, listIntelSourceListVos);
这个list中存放的类定义如下:
@EqualsAndHashCode(callSuper = true)
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class IntelSourceListVo extends ComparableImpl<IntelSourceListVo> {
private int sourceId;
private String sourceName;
private int sourceType;
private String intelType;
private String intelUri;
private long validCount;
private long totalCount;
private String createtime;
private String lastEnteringTime;
private int status;
private int weight;
private Integer isStart;
}
它实现的comparableImpl为一个自定义的排序类,实现这个排序类的类可以根据类中的sortType来进行排序,orderBy进行升序与降序的控制。其中用到了一些简单的反射。
package cn.threatbook.tim.vo;
import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import org.apache.commons.lang3.StringUtils;
import java.lang.reflect.Field;
@Setter
@Getter
@NoArgsConstructor
public class ComparableImpl<T> implements Comparable<T> {
@JsonIgnore
String sortType;
@JsonIgnore
String orderBy;
@Override
public int compareTo(T that) {
if (orderBy == null) {
return 0;
}
int order = -1;
if ("desc".equals(sortType)) {
order = 1;
}
try {
Class clazz = that.getClass();
Field field = clazz.getDeclaredField(orderBy);
field.setAccessible(true);
Object thisValue = field.get(this);
Object thatValue = field.get(that);
String valueType = field.getType().toString();
if (valueType.endsWith("String")) {
String thisValueStr = (String) thisValue;
String thatValueStr = (String) thatValue;
if (StringUtils.isEmpty(thisValueStr)
&& StringUtils.isEmpty(thatValueStr)) {
return 0;
} else if (StringUtils.isEmpty(thisValueStr)) {
return order;
} else if (StringUtils.isEmpty(thatValueStr)) {
return -order;
}
return -thisValueStr.compareTo(thatValueStr) * order;
} else if (valueType.endsWith("long") || valueType.endsWith("Long")) {
//bug出现处
long thisValueLong = (long) thisValue;
long thatValueStr = (long) thatValue;//这随意的变量命名....
return (int) (thatValueStr - thisValueLong) * order;
} else if (valueType.endsWith("int") || valueType.endsWith("Integer")) {
int thisValueLong = (int) thisValue;
int thatValueStr = (int) thatValue;
return (thatValueStr - thisValueLong) * order;
}
} catch (Exception e) {
e.printStackTrace();
}
return 0;
}
}
由于请求参数orderBy=validCount&sortType=desc¤tPage=1 中指定了的排序字段是validCount
且该实体类的validCount字段为long类型,可知排序肯定在long类型比较的代码块中进行。
断点debug到long类型进行比较的部分 发现了该bug产生的原因。主要原因是当两个值进行相减后
比如2822920460-1 结果依旧大于Integer.MAX_VALUE ,在进行int强转后,返回的结果不准确。
public static void main(String[] args) {
long l = -2822920460L;
System.out.println((int) l);
l = 2822920460L;
System.out.println((int) l);
}
输出的结果为:
可以看到符号正好是相反的。
将代码进行修改后 完成。
今天又修好了一个bug 也少了几根头发
- WCF技术剖析(卷1)之前言
- WCF技术剖析(卷1)之目录
- WCF技术剖析(卷1)之推荐序
- 谈谈基于SQL Server 的Exception Handling[上篇]
- 谈谈WCF中的Data Contract(4):WCF Data Contract Versioning
- 如何在silverlihgt中使用右键
- WCF技术剖析之十二:数据契约(Data Contract)和数据契约序列化器(DataContractSerializer)
- silverlight向服务器post数据类
- WCF技术剖析之十三:序列化过程中的已知类型(Known Type)
- 44 Amazing Silverlight 2.0 Screencasts
- CaseStudy(showcase)类库篇-用agTweener来实现动画效果
- CaseStudy(showcase)数据篇-Loading的制作
- CaseStudy(showcase)数据篇-加载图片
- CaseStudy(showcase)数据篇-从XML中获取数据
- java教程
- Java快速入门
- Java 开发环境配置
- Java基本语法
- Java 对象和类
- Java 基本数据类型
- Java 变量类型
- Java 修饰符
- Java 运算符
- Java 循环结构
- Java 分支结构
- Java Number类
- Java Character类
- Java String类
- Java StringBuffer和StringBuilder类
- Java 数组
- Java 日期时间
- Java 正则表达式
- Java 方法
- Java 流(Stream)、文件(File)和IO
- Java 异常处理
- Java 继承
- Java 重写(Override)与重载(Overload)
- Java 多态
- Java 抽象类
- Java 封装
- Java 接口
- Java 包(package)
- Java 数据结构
- Java 集合框架
- Java 泛型
- Java 序列化
- Java 网络编程
- Java 发送邮件
- Java 多线程编程
- Java Applet基础
- Java 文档注释
- 二层网络上的以太坊智能合约: Optimistic Rollup
- 基于决策树的工业数据分类——数据智能
- Kestrel的ListenAnyIP和ListenLocalhost的区别
- 【为宏正名】什么?我忘了去上“数学必修课”!
- 第6章 Jenkins系统权限划分与授权管理
- Python爬虫新手教程: 知乎文章图片爬取器
- 《重构-代码整洁之道TypeScript版》第4天
- C++基础 杂记(一)
- 一种Cortex-M内核中的精确延时方法(ns级别)
- 算法集锦(17)|自然语言处理| 比特币市场情绪分析算法
- Linux匿名管道及实例
- 查找算法笔记(C++版)
- C++基础 指针使用注意
- FreeRTOS移植-基于STM32F407
- 感知机的股票预测算例及python代码实现 | 山人聊算法 | 5th