Issue
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
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 itconvertTo
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.
Answered By - rzwitserloot
Answer Checked By - David Goodson (JavaFixing Volunteer)