• 神奇在 Double 转换异常


    异常

    线上收到告警, 有以下异常

    java.lang.ArithmeticException: input is infinite or NaN
            at com.google.common.math.DoubleMath.roundIntermediate(DoubleMath.java:59)
            at com.google.common.math.DoubleMath.roundToLong(DoubleMath.java:156)
    
            .......................
    

    代码

    对应的业务代码如下:

    public static Long formatLongDefaultNegativeOne(Object obj) {
            String objStr = String.valueOf(obj);
            return !StringUtils.isBlank(objStr) &&
                   !objStr.equals("NaN") && 
                   !objStr.equals("Infinity") && 
                   !objStr.equals("null") ? 
                        DoubleMath.roundToLong(Double.valueOf(String.valueOf(obj)),  RoundingMode.HALF_EVEN) : 
                        -1L;
        }
    

    抛出异常的地方做了如下判断:

    ......
        if (!isFinite(x)) {
          throw new ArithmeticException("input is infinite or NaN");
        }
    ......
    ......
    //判断是否在有限范围内
    static boolean isFinite(double d) {
        return getExponent(d) <= MAX_EXPONENT;
    }
    

    getExponent(d) 是获取当前 double值的指数 . MAX_EXPONENTDouble最大值的指数 .

    getExponent(d) 的方法注释中有以下说明:

    If the argument is NaN or infinite, then the result is Double.MAX_EXPONENT + 1.

    If the argument is zero or subnormal, then the result is Double.MIN_EXPONENT -1.

    判断不在有效范围内的, 只有两种情况 , double 值是 NaNInfinity .

    分析

    主要逻辑都在这行代码中:

    DoubleMath.roundToLong(Double.valueOf(String.valueOf(obj)))
    

    从上面的异常中可以得知 , DoubleMath.roundToLong方法得到是 NaNInfinity . 即 Double.valueOf() == NaN || Double.valueOf() == Infinity .

    业务方法的这个代码 formatLongDefaultNegativeOne(Object obj) 是从上游获取的数值 , 业务上已经限定了只能是数值类型. 对于从上游得到的数值 , 理论上是只有这几种情况了.

    • null
    • NaN
    • Infinity
    • 正常数值

    对于前三种 , 逻辑上已经做了判断 , 但结果还是抛出了异常 . 说明数值不在上面四种情况里 .

    当前也没有想法具体是什么样的数值才能导致这个异常 . 由于缺少线上数据的支撑 , 无法继续下去 . 只能后面再解决定位了.

    未完待续.......

    后记

    线上加了日志, 才终于发现了问题。

    这个数据是 -Infinity 。 是负无限 !

    本应是正数计算的逻辑里, 竟然出现了负数。 所以一直也没往负数的方向上去想。

    找到问题就好解决了 。

    • 解决业务里出现负数的业务逻辑
    • 不兼容负数场景 , 但要有个 try - catch 。

    这个神奇的异常算是结束了。 同时也做了个警醒 , 对待无限 , 有正无限, 还有负无限!


    如果文章有帮助到您,请点个赞,您的反馈会让我感到文章是有价值的

  • 相关阅读:
    Delphi XE5 图解为Android应用制作签名
    Delphi事件的广播 转
    Delphi XE6 Android拨号函数
    Firemonkey里触发home按键被按下的事件
    如何处理App的Application的事件
    SQL SERVER存储过程中使用事务与捕获异常
    关于蓝牙打印机的开发
    图标大全网站
    提高Android和iOS调试编译速度
    百万级数据查询优化(数据库)
  • 原文地址:https://www.cnblogs.com/ElEGenT/p/13159506.html
Copyright © 2020-2023  润新知