`
welcomezhang
  • 浏览: 16855 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

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

阅读更多

 

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

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics