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