BigDecimal类中的String参数类型的构造器(Java)

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这三个数字也判断是数字,前置多余的零忽略去掉了

上一篇:nginx启动及其他操作报错踩坑


下一篇:java 金额计算