在項目中遇到一處bug,調試的結果竟然是StringUtils.isNumeric(String str) 在搗鬼(采用的是org.apache.commons.lang.StringUtils),下面的代碼是判斷一個參數非空,且為整數:
if(StringUtils.isNumeric(str) && StringUtils.isNotBlank(str)){ // do sth }
在簡單不過的代碼,卻隱藏着bug !
因為如果 str = "-1"; StringUtils.isNumeric(str) 返回的是 false! 真是肯爹不償命啊。
下面是測試:
public static void main(String[] args) { System.out.println(StringUtils.isNumeric("-1")); }
運行結果:false
肯爹吧?用正則表達式實現不是很簡單嗎?怎么會這樣,看了下源碼:
public static boolean isNumeric(String str) { if (str == null) { return false; } int sz = str.length(); for (int i = 0; i < sz; i++) { if (Character.isDigit(str.charAt(i)) == false) { return false; } } return true; }
繼續跳進去:
public static boolean isDigit(char ch) { return isDigit((int)ch); }
繼續:
public static boolean isDigit(int codePoint) { boolean bDigit = false; if (codePoint >= MIN_CODE_POINT && codePoint <= FAST_PATH_MAX) { bDigit = CharacterDataLatin1.isDigit(codePoint); } else { int plane = getPlane(codePoint); switch(plane) { case(0): bDigit = CharacterData00.isDigit(codePoint); break; case(1): bDigit = CharacterData01.isDigit(codePoint); break; case(2): bDigit = CharacterData02.isDigit(codePoint); break; case(3): // Undefined case(4): // Undefined case(5): // Undefined case(6): // Undefined case(7): // Undefined case(8): // Undefined case(9): // Undefined case(10): // Undefined case(11): // Undefined case(12): // Undefined case(13): // Undefined bDigit = CharacterDataUndefined.isDigit(codePoint); break; case(14): bDigit = CharacterData0E.isDigit(codePoint); break; case(15): // Private Use case(16): // Private Use bDigit = CharacterDataPrivateUse.isDigit(codePoint); break; default: // the argument's plane is invalid, and thus is an invalid codepoint // bDigit remains false; break; } } return bDigit; }
在下面一步失敗:
static boolean isDigit(int ch) { int type = getType(ch); return (type == Character.DECIMAL_DIGIT_NUMBER); }
也就是說他的實現完全沒有考慮到 - + 前綴的問題,這不是傻叉嗎?
下面的結果都是 false:
public static void main(String[] args) { System.out.println(StringUtils.isNumeric("-1")); System.out.println(StringUtils.isNumeric("+1")); }
這是他的方法注釋:
Checks if the String contains only unicode digits. A decimal point is not a unicode digit and returns false. null will return false. An empty String ("") will return true. StringUtils.isNumeric(null) = false StringUtils.isNumeric("") = true StringUtils.isNumeric(" ") = false StringUtils.isNumeric("123") = true StringUtils.isNumeric("12 3") = false StringUtils.isNumeric("ab2c") = false StringUtils.isNumeric("12-3") = false StringUtils.isNumeric("12.3") = false Parameters: str the String to check, may be null Returns: true if only contains digits, and is non-null
只能包含 unicode 的數字, +, -, . 三者都不能算作是unicode 數字。
