最近有个低级错误,导致线上bug。情况是这样的:
业务需求
需要写一个方法,判断createTime在60天以内的记录才有效,才有资格进行后续的抽奖操作。
实现
private boolean drawTimeExpired(Date createTime) { if (createTime == null) { errorLogger.error(genErrorInfo(IMPOSSIBLE_CONDITION, "createTime null", "drawTimeExpired")); return false; } return new DateTime().getMillis() > createTime.getTime() + 60 * 24 * 3600 * 1000; }
这样写有问题么?
——乍一看,没毛病啊。
60天*24小时*60分*60s*1000ms
测试一下
用1天和61天分别测试一下看看
public static void main(String[] args) throws Exception{ DateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); Date createTime = sdf.parse("2017-04-09 13:14:15"); System.out.println(new DateTime().getMillis() > createTime.getTime() + 60 * 24 * 3600 * 1000); //false Date createTime2 = sdf.parse("2017-02-08 13:14:15"); System.out.println(new DateTime().getMillis() > createTime2.getTime() + 60 * 24 * 3600 * 1000); //true }
看结果,还是没毛病啊~
再用15天测试一下
public static void main(String[] args) throws Exception{ DateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); Date createTime3 = sdf.parse("2017-03-25 13:14:15"); System.out.println(new DateTime().getMillis() > createTime3.getTime() + 60 * 24 * 3600 * 1000); }
结果是true。
咦!这咋回事,3月25号肯定没超过60天啊,颠覆世界观了?
再仔细debug一下,发现了问题所在
System.out.println(60 * 24 * 3600 * 1000);//889032704 System.out.println(60 * 24 * 3600 * 1000L);//5184000000
这是咋回事呢?
整数越界了,60天的毫秒数吵过了整数的最大值。
那我们来看一下 java各数据类型的取值范围:
public static void main(String[] args) throws Exception{ System.out.println("Integer.MIN_VALUE = " + Integer.MIN_VALUE); System.out.println("Integer.MAX_VALUE = " + Integer.MAX_VALUE); System.out.println("Long.MIN_VALUE = " + Long.MIN_VALUE); System.out.println("Long.MAX_VALUE = " + Long.MAX_VALUE); System.out.println("Float.MIN_VALUE = " + Float.MIN_VALUE); System.out.println("Float.MIN_NORMAL = " + Float.MIN_NORMAL); System.out.println("Float.MAX_VALUE = " + Float.MAX_VALUE); System.out.println("Double.MAX_VALUE = " + Double.MAX_VALUE); System.out.println("Double.MIN_VALUE = " + Double.MIN_VALUE); }
结果如下:
Integer.MIN_VALUE = -2147483648 Integer.MAX_VALUE = 2147483647 Long.MIN_VALUE = -9223372036854775808 Long.MAX_VALUE = 9223372036854775807 Float.MIN_VALUE = 1.4E-45 Float.MIN_NORMAL = 1.17549435E-38 Float.MAX_VALUE = 3.4028235E38 Double.MAX_VALUE = 1.7976931348623157E308 Double.MIN_VALUE = 4.9E-324
整数最大值为:2147483647
2147483647/24/3600/1000=24.85..天
fix措施
1.25天以内可以用Interger
2.求天数的毫秒数这种情况一律用范围更广的Long类型来表示。
fix后的代码:
private boolean drawTimeExpired(Date createTime) { if (createTime == null) { errorLogger.error(genErrorInfo(IMPOSSIBLE_CONDITION, "createTime null", "drawTimeExpired")); return false; } return new DateTime().getMillis() > createTime.getTime() + 60 * 24 * 3600 * 1000L; }
看出来了么?只加了一个L。
小结
有时候一个好的编程习惯会帮你规避一些容易范的小错。
比如大数切记用Long,而不需要死记各类型的取值范围
比如相等比较用equals,而不是“==”
相关推荐
义一个整数集合类integerSet。这种类型的对象可以存储10个20~80之间的整数,即他的内部有一个整型数组存储数据。编程: (1) 判断两个inergerSet类对象S1和S2是否相等。提示:集合相等的前提是所有元素相等。 (2)...
集合类 C++ 面向对象
由于使用模板,所以只有一个Integer.h头文件 支持如下操作:>, >=, <, , ==, !=, +, +=, -, -=, *, =, /, /=,(输出);支持利用基本整数类型(int,unsigned,long long,……)和字符串(char和std::string)构造类型
HugeInteger Class) Create a class HugeInteger that uses a 40-element array of digits to store integers as large as 40 digits each. Provide member functions input, output, add and subtract. For ...
Transform Coding with Integer-to-Integer Transforms.pdf H.264學習資料
创建一个大整数类HugeInteger,该类用一个40个元素的数组来存放一个大整数(最多不超过40位)。 构造函数原型: HugeInteger(String); (1)定义几个大整数算术运算的成员函数,包括input、output、add和sub, add, ...
Clock_Integer 指令库应用例程rar,Clock_Integer 指令库应用例程
mybatis返回int会报错,改成Integer封装类型可以解决,具体参考我的博客
HugeInteger.java
bigdecimal转integer
实现1~40为的整数(超过int、long等类型的范围)的加减乘除
Gaussian Integer
Mybatis Generator将tinyint映射成Integer的解决办法
Logic and Integer Programming
巨大整数创建一个服务HugeInteger,该服务使用40个元素的数字数组存储每个最大40位数字的整数。 提供解析,toString,加法和减法的方法。 方法解析应该接收一个字符串,使用charAt方法提取每个数字,并将每个数字的...
c++ 大整数库 big integer 来自https://mattmccutchen.net/bigint/
mybatis逆向工具generator,中文注释,把自动生成的Byte改成了Integer
前端项目-big-integer,An arbitrary length integer library for Javascript
北大POJ1503-Integer Inquiry 解题报告+AC代码