Search code examples
javanumbersnumber-formatting

How to cast from String to BigDecimal with the separator as a comma?


I have a method to set a BigDecimal number that is given as String:

private Client mapClient(Client client){
   ClientRequest clientRequest = new ClientRequest();
   // Code
   clientRequest.setCashAmount(castStringToBigDecimal(client.getCashAmount()));
   // More Code
}

My castStringToBigDecimal method is the follosing:

public BigDecimal castStringToBigDecimal(String value){
   BigDecimal response = null;
      if(value != null && !value.equals("")){
          value = value.replaceAll("[.]", ",");
          response = new BigDecimal(value);
      }

  return response;
}

An example of the input value is "1554.21"

I need that the bigDecimal separator to be a comma, not a dot. But this is giving me an exception.

EDIT

The value is the following: enter image description here

And the exception is:

java.lang.NumberFormatException: Character , is neither a decimal digit number, decimal point, nor "e" notation exponential mark.

Solution

  • BigDecimal doesn't represent a rendering. In other words, whether to use a comma or a dot as separator is not part of the properties a BigDecimal object has.

    Hence, you do not want to call .replaceAll. (And separately, you'd want .replace(".", ",") - replace replaces all, and replaceAll also replaces all and interprets the first arg as a regex, and is therefore needlessly confusing here). Just pass it with the dot.

    To render a BigDecimal, don't just sysout it, that will always show a dot and there is nothing you can do about that. toString() is almost never the appropriate tool for the job of rendering data to a user - it's a debugging aid, nothing more. Use e.g. String.format("%f"), specifying the appropriate locale. Or use NumberFormat. The javadoc of BigDecimal explicitly spells this out.

    There are various other issues with your code:

    • "cast" is the technical name for the syntactic construct: (Type) expr; - and this construct does 3 utterly different things, hence using it to describe a task, i.e. use it in a method name, is a very bad idea. In particular, only one of the 3 things it does converts anything, and you clearly use it here in the 'convert something' meaning. This is misleading; only if it's all primitives does the cast operator convert, and BigDecimal isn't primitive. Call it convertTo or whatever you please, not "cast".
    • BigDecimal is an extremely complicated tool for the job and usually not the right tool if you want to represent financial data. Instead, represent the atomary unit in a long and call the appropriate rendering method whenever you need to show it to a user. For example, for euros, the atomary unit is the eurocent. If something costs €1,50, you'd store "150", in a long. Before you think: But, wait, I want to divide, and then I'd lose half a cent! - yes, well, you can't exactly send your bank a request to transfer half a cent, either. Also, try to divide 4 cents by 3 with a BigDecimal and see what happens. Dividing financial amounts is tricky no matter what you use, BD isn't a catch-all solution to this problem.