Search code examples
javastringbigdecimaltypeconverter

Convert String to BigDecimal without losing format


I'm trying to convert a string to a BigDecimal but I can't manage to preserve the format. the String is a price/number with a format which can either be #,###.00 or # ###,00

this is what i've tried but it doesn't keep the format intact. 37,717,840.33 ==> 37717840.33

public static BigDecimal convertStringtoDecimal(String patternDecimalFormat, 
String pattern, String price) { 

    DecimalFormatSymbols symbols = new DecimalFormatSymbols();
    symbols.setDecimalSeparator(pattern.charAt(0));
    symbols.setGroupingSeparator(pattern.charAt(1));
    DecimalFormat decimalFormat = new DecimalFormat(patternDecimalFormat, symbols);
    decimalFormat.setParseBigDecimal(true);

    BigDecimal bigDecimal = null;
    try {
        bigDecimal = (BigDecimal) decimalFormat.parse(price);
    } catch (ParseException e) { 

        LOGGER.warn("Exception convertion string to dec", e);
    }
    return bigDecimal ;

}

Solution

  • A BigDecimal is an "[i]mmutable, arbitrary-precision signed decimal number[]".

    What is "arbitrary-precision"? This Wikipedia article has this to say in its introduction:

    In computer science, arbitrary-precision arithmetic, also called bignum arithmetic, multiple-precision arithmetic, or sometimes infinite-precision arithmetic, indicates that calculations are performed on numbers whose digits of precision are limited only by the available memory of the host system. This contrasts with the faster fixed-precision arithmetic found in most arithmetic logic unit (ALU) hardware, which typically offers between 8 and 64 bits of precision.

    In other words, BigDecimal is a special type of Number that allows "perfect" (it can't handle irrational numbers) precision. This is in contrast to Double (or the primitive type, double) which has "fixed-precision" and therefore can't represent all the numbers that BigDecimal can. This increase in precision comes at the cost of increased memory use and much slower mathematical operations (computers can handle doubles and such at a hardware level).

    Why am I bringing all this up? Because I want to point out that a BigDecimal is nothing more than a fancy number. And numbers, at least in Java, have no concept of formatting. With that in mind you realize it makes no sense to expect a BigDecimal to maintain the format of the String used to create it. There are hints at this in your own code; you had to use the intermediary DecimalFormat object to parse your String into a BigDecimal. Why would you have to do this when BigDecimal has a constructor that takes a String? It's because the BigDecimal constructor is very limited. If you were to try to convert your String using the constructor you'd get a NumberFormatExcepton with the following message: "Character , is neither a decimal digit number, decimal point, nor "e" notation exponential mark."

    As you can see, it is the DecimalFormat that understands the String in your code. The reason for this is because that's what DecimalFormat is designed for. The class exists so you can parse Strings into Numbers and Numbers into Strings using a specified pattern (which is normally based on the user's Locale). When you want to display a Number such as a BigDecimal but in a formatted fashion you have to use a class such as DecimalFormat. Some options to convert a number into a String would be:

    As I pointed out in the question comments, in your case you should be able to get back the formatted String by calling

    String formattedString = decimalFormat.format(bigDecimal);
    

    on the same DecimalFormat or at least one that was configured the same.