神奇在 Double 转换异常 input is infinite or NaN

异常

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

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
  • 正常数值

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

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

未完待续.......


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

猜你喜欢

转载自www.cnblogs.com/ElEGenT/p/13159506.html
NaN