神奇在 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
  • 正常數值

對於前三種 , 邏輯上已經做了判斷 , 但結果還是拋出了異常 . 說明數值不在上面四種情況裏 .

當前也沒有想法具體是什麼樣的數值才能導致這個異常 . 由於缺少線上數據的支撐 , 無法繼續下去 . 只能後面再解決定位了.

未完待續.......


如果文章有幫助到您,請點個贊,您的反饋會讓我感到文章是有價值的

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章