JDK 8
调用传入String类型的参数的构造器
public BigDecimal(String val) { this(val.toCharArray(), 0, val.length()); }
最终调用的是下面这个方法
/** * @param in String类对象各单个字符组成的char数组 * @param offset 初始为0 * @param len String对象的长度 * @param mc 这里传入的是MaxContext.UNLIMITED, 不限制有效位数, 采用四舍五入 */ public BigDecimal(char[] in, int offset, int len, MathContext mc)
public BigDecimal(char[] in, int offset, int len, MathContext mc) { // protect against huge length. if (offset + len > in.length || offset < 0) throw new NumberFormatException("Bad offset or len arguments for char[] input."); // This is the primary string to BigDecimal constructor; all // incoming strings end up here; it uses explicit (inline) // parsing for speed and generates at most one intermediate // (temporary) object (a char[] array) for non-compact case. // Use locals for all fields values until completion int prec = 0; // 有效数字位数 int scl = 0; // 小数点后有几位数 long rs = 0; // the compact value in long BigInteger rb = null; // the inflated value in BigInteger // use array bounds checking to handle too-long, len == 0, // bad offset, etc. try { // handle the sign boolean isneg = false; // assume positive if (in[offset] == '-') { isneg = true; // leading minus means negative offset++; len--; } else if (in[offset] == '+') { // leading + allowed offset++; len--; } // should now be at numeric part of the significand boolean dot = false; // true when there is a '.' long exp = 0; // exponent char c; // current character boolean isCompact = (len <= MAX_COMPACT_DIGITS); // integer significand array & idx is the index to it. The array // is ONLY used when we can't use a compact representation. int idx = 0; if (isCompact) { // First compact case, we need not to preserve the character // and we can just compute the value in place. for (; len > 0; offset++, len--) { c = in[offset]; if ((c == '0')) { // have zero if (prec == 0) prec = 1; else if (rs != 0) { rs *= 10; ++prec; } // else digit is a redundant leading zero if (dot) ++scl; } else if ((c >= '1' && c <= '9')) { // have digit int digit = c - '0'; if (prec != 1 || rs != 0) ++prec; // prec unchanged if preceded by 0s rs = rs * 10 + digit; if (dot) ++scl; } else if (c == '.') { // have dot // have dot if (dot) // two dots throw new NumberFormatException(); dot = true; } else if (Character.isDigit(c)) { // slow path int digit = Character.digit(c, 10); if (digit == 0) { if (prec == 0) prec = 1; else if (rs != 0) { rs *= 10; ++prec; } // else digit is a redundant leading zero } else { if (prec != 1 || rs != 0) ++prec; // prec unchanged if preceded by 0s rs = rs * 10 + digit; } if (dot) ++scl; } else if ((c == 'e') || (c == 'E')) { exp = parseExp(in, offset, len); // Next test is required for backwards compatibility if ((int) exp != exp) // overflow throw new NumberFormatException(); break; // [saves a test] } else { throw new NumberFormatException(); } } if (prec == 0) // no digits found throw new NumberFormatException(); // Adjust scale if exp is not zero. if (exp != 0) { // had significant exponent scl = adjustScale(scl, exp); } rs = isneg ? -rs : rs; int mcp = mc.precision; int drop = prec - mcp; // prec has range [1, MAX_INT], mcp has range [0, MAX_INT]; // therefore, this subtract cannot overflow if (mcp > 0 && drop > 0) { // do rounding while (drop > 0) { scl = checkScaleNonZero((long) scl - drop); rs = divideAndRound(rs, LONG_TEN_POWERS_TABLE[drop], mc.roundingMode.oldMode); prec = longDigitLength(rs); drop = prec - mcp; } } } else { char coeff[] = new char[len]; for (; len > 0; offset++, len--) { c = in[offset]; // have digit if ((c >= '0' && c <= '9') || Character.isDigit(c)) { // First compact case, we need not to preserve the character // and we can just compute the value in place. if (c == '0' || Character.digit(c, 10) == 0) { if (prec == 0) { coeff[idx] = c; prec = 1; } else if (idx != 0) { coeff[idx++] = c; ++prec; } // else c must be a redundant leading zero } else { if (prec != 1 || idx != 0) ++prec; // prec unchanged if preceded by 0s coeff[idx++] = c; } if (dot) ++scl; continue; } // have dot if (c == '.') { // have dot if (dot) // two dots throw new NumberFormatException(); dot = true; continue; } // exponent expected if ((c != 'e') && (c != 'E')) throw new NumberFormatException(); exp = parseExp(in, offset, len); // Next test is required for backwards compatibility if ((int) exp != exp) // overflow throw new NumberFormatException(); break; // [saves a test] } // here when no characters left if (prec == 0) // no digits found throw new NumberFormatException(); // Adjust scale if exp is not zero. if (exp != 0) { // had significant exponent scl = adjustScale(scl, exp); } // Remove leading zeros from precision (digits count) rb = new BigInteger(coeff, isneg ? -1 : 1, prec); rs = compactValFor(rb); int mcp = mc.precision; if (mcp > 0 && (prec > mcp)) { if (rs == INFLATED) { int drop = prec - mcp; while (drop > 0) { scl = checkScaleNonZero((long) scl - drop); rb = divideAndRoundByTenPow(rb, drop, mc.roundingMode.oldMode); rs = compactValFor(rb); if (rs != INFLATED) { prec = longDigitLength(rs); break; } prec = bigDigitLength(rb); drop = prec - mcp; } } if (rs != INFLATED) { int drop = prec - mcp; while (drop > 0) { scl = checkScaleNonZero((long) scl - drop); rs = divideAndRound(rs, LONG_TEN_POWERS_TABLE[drop], mc.roundingMode.oldMode); prec = longDigitLength(rs); drop = prec - mcp; } rb = null; } } } } catch (ArrayIndexOutOfBoundsException e) { throw new NumberFormatException(); } catch (NegativeArraySizeException e) { throw new NumberFormatException(); } this.scale = scl; this.precision = prec; this.intCompact = rs; this.intVal = rb; }
从源码中截取一部分代码,我们来看看Character.isDigit(char c)
这个方法
for (; len > 0; offset++, len--) { c = in[offset]; if ((c == '0')) { // have zero if (prec == 0) prec = 1; else if (rs != 0) { rs *= 10; ++prec; } // else digit is a redundant leading zero if (dot) ++scl; } else if ((c >= '1' && c <= '9')) { // have digit int digit = c - '0'; if (prec != 1 || rs != 0) ++prec; // prec unchanged if preceded by 0s rs = rs * 10 + digit; if (dot) ++scl; } else if (c == '.'){ // 略 } else if (Character.isDigit(c)) { // slow path int digit = Character.digit(c, 10); if (digit == 0) { if (prec == 0) prec = 1; else if (rs != 0) { rs *= 10; ++prec; } // else digit is a redundant leading zero } else { if (prec != 1 || rs != 0) ++prec; // prec unchanged if preceded by 0s rs = rs * 10 + digit; } if (dot) ++scl; }
当时在看这段代码时,不明白为什么在已经判断了字符是否为0~9
,还要在后面调用Character.isDigit(char c)
去判断是否是数字, 查看JDK8文档
Some Unicode character ranges that contain digits: '\u0030' through '\u0039', ISO-LATIN-1 digits ('0' through '9') '\u0660' through '\u0669', Arabic-Indic digits '\u06F0' through '\u06F9', Extended Arabic-Indic digits '\u0966' through '\u096F', Devanagari digits '\uFF10' through '\uFF19', Fullwidth digits
原来Unicode
字符集中还有其他编码范围也是表示数字,做一下编码转换,这些数字如下
Arabic-Indic digits '٠' '١' '٢' '٣' '٤' '٥' '٦' '٧' '٨' '٩' Extended Arabic-Indic digits '۰' '۱' '۲' '۳' '۴' '۵' '۶' '۷' '۸' '۹', Devanagari digits '०' '१' '२' '३' '४' '५' '६' '७' '८' '९', Fullwidth digits '0' '1' '2' '3' '4' '5' '6' '7' '8' '9'
调用BigDecimal
的单个String
参数的构造器方法,可以判断该字符串是否是数字
import java.math.BigDecimal; public class Test { public static void main(String[] args) { String[] strArr = { "123", "123.1", " 1.0", "123..1", "abc", "1.1 ", "00.01", "001.01", "0101", "0x10" }; for (String s : strArr) { try { BigDecimal bigDecimal = new BigDecimal(s); System.out.println(s + "是一个数字, 转换后的BigDecimal是" + bigDecimal); } catch (NumberFormatException e) { System.out.println(s + "不是一个数字"); } } } }
123是一个数字, 转换后的BigDecimal是123 123.1是一个数字, 转换后的BigDecimal是123.1 1.0不是一个数字 123..1不是一个数字 abc不是一个数字 1.1 不是一个数字 00.01是一个数字, 转换后的BigDecimal是0.01 001.01是一个数字, 转换后的BigDecimal是1.01 0101是一个数字, 转换后的BigDecimal是101 0x10不是一个数字
00.01
,001.01
,0101
这三个数字也判断是数字,前置多余的零忽略去掉了