带逗号的数值字符串转BigDecimal
项目需要将带有逗号的数值字符串转换为Money类型的数据,Money类型需要通过BigDecimal类型来构造。于是需要先将字符串转为BigDecimal类型。
字符串数据是带有逗号的,例:"25,000"。需要对字符串进行处理才能转换为BigDecimal。
version1: 先用replace将字符串里的逗号去掉,再构造BigDecimal
public BigDecimal createBigDecimalFromString(String str) {
try {
String replaced = str.replace(",", "");
BigDecimal result = new BigDecimal(replaced);
return result;
} catch (NumberFormatException e) {
return null;
但是,用replace方法修改字符串并不优雅,有没有更好的方法可以直接读取该格式的字符串呢。
发现有DecimalFormat类,可以用它来直接读取带有逗号的数值字符串。
version2:用NumberFormat读取字符串,得到Number类型对象。用DecimalFormat将Number转为String类型,再通过String构造BigDecimal(注:new DecimalFormat("#")是因为该案例里的数值都是整数。"#"表示取整数,"#.##"表示取整数及小数点后2位)
private BigDecimal createBigDecimalUseDecimalFormat(String str) {
DecimalFormat format = new DecimalFormat();
// or
// NumberFormat format = NumberFormat.getInstance();
// NumberFormat format = new DecimalFormat();
try {
Number resultNumber = format.parse(str);
DecimalFormat dfFormat = new DecimalFormat("#");
String numberStr = dfFormat.format(resultNumber);
BigDecimal result = new BigDecimal(numberStr);
return result;
} catch (ParseException e) {
return null;
该版本有一个很大的问题,就是Number转为String类型时可能出现精度损失。例如处理字符串"1,000,000,222,111,444,333,555",将其转换为Number类型会成为"1.0000002221114444E21",再转为String变成"1000000222111444400000"。精度损失是绝对不允许的。似乎Number类型没有将Number转为BigDecimal的方法。怎么办呢。
查询Stack Overflow,发现在使用DecimalFormat读取数值字符串之前,可以调用DecimalFormat的setParseBigDecima,它可以设置读取字符串时是否可以parse为BigDecimal,在读取数值字符串时,通过强制类型转换得到BigDecimal。
version3:
private BigDecimal readStrAsBigDecimal(String str) {
DecimalFormat format = new DecimalFormat();
format.setParseBigDecimal(true);
try {
BigDecimal parse = (BigDecimal) format.parse(str);
return parse;
} catch (ParseException e) {
e.printStackTrace();
return null;
经过测试,该方法不会再有精度损失了。但是在测试时发现,如果在数值字符串的中间或者末尾加入字母,parse时也不会抛出异常。例如:"1,000,000,222,111,444,333,555aaa"转换后会得到结果"1000000222111444333555";"1,000aaa,000,222,111,444,333,555"转换后得到结果"1000"。这也不是我们想要的结果,因为我们的数据本身存在一些带有字母异常数据,而我们不能将异常数据当做正常数据进行处理。
在读取字符串时使用的parse方法有一个带有两个入参的实现:public Number parse(String text, ParsePosition pos);pos会记录parse结果的最后一位在原字符串中的位置。如果字符串完全由数值和数值分隔符号组成的话,那parse结束后pos的位置应该等于该字符串的长度。例:"1,000"parse结束后,pos的index值应该为5,等于字符串长度;"1,000a,00"parse结束后,pos的index值为5,不等于字符串长度9。我们可以通过pos值来判断被处理的字符串是否是异常字符串。(parse(String text, ParsePosition pos)方法不会抛出任何异常)
version4:
public BigDecimal readStrAsBigDecimalAndCheckFormat(String str) {
DecimalFormat format = new DecimalFormat();
format.setParseBigDecimal(true);
ParsePosition position = new ParsePosition(0);
BigDecimal parse = (BigDecimal) format.parse(str, position);
if (str.length() == position.getIndex()) {
return parse;
return null;
使用该方法成功将原字符串转为了没有精度损失的BigDecimal类型,并且不会由异常源数据得到错误结果。