论坛首页 编程语言技术论坛

一个Interger越界引发的线上问题

浏览 3343 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2017-04-09  

 

需要有个低级错误,导致线上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

 

测试一下

 

    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
    }

 

 

看结果,还是没毛病啊~

 

再测试一下

 

    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天啊,颠覆世界观了?

 

再测试一下,发现了问题所在

 

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..天

 

改进措施

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,而不是“==”

   发表时间:2017-04-12  
不确定大小的话可以使用biginteger,性能稍低于主类型。但绝对不会导致数值溢出的问题。除非计算器内存不足。
0 请登录后投票
   发表时间:2017-04-12  
另外提一句,比较对象的话可以使用Objects.equals(a,b)方法,很简单的就避免了空指针异常。此方法在jdk1.7之后版本均可使用。
0 请登录后投票
论坛首页 编程语言技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics