JDK版本: 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)
从源码中截取一部分代码,我们来看看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
这三个数字也判断是数字,前置多余的零忽略去掉了