最近有个低级错误,导致线上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,而不是“==”