I work at a financial firm and almost all of the income related fields in our application are declared as "String" instead of double or BigDecimal. Is this an acceptable thing to do? I'd have thought that we shouldn't be using strings for income.
Could someone please help me understand?
It's possible that there was a good reason for that decision, or maybe a reason which was a good reason back when the decision was made. You never know; for example it might have had something to do with interfacing with some ancient system which is no longer around. Or on the other hand it may be that the designers didn't know any better. But from here it's impossible to tell.
I can see how you might not want to ask within your organization, though. It's possible that the designers in question are now in senior positions and you might be seen as questioning their judgement. Which might cause trouble for you in some environments. On the other hand it might be that your senior staff inherited this application from people who are no longer around, in which case they might well agree with you about your instinct. Again it's impossible to tell.
I am thinking about how I should do this now.
Let's say the reason for using Strings is that they need an easy way to handle money at the front-end. There's nothing stopping a back-end developer to use BigInteger/BigDecimal wherever they can, and before sending data back to the client, do a conversion to String, and when you receive money as a String, convert it to BigInteger/BigDecimal.
I agree with Paul though that consistency is most important, and you may want to stick with what you have until you manage to convince your project lead that it's okay to replace strings with better types as you go.
Also, how would I convert from String to BigDecimal on the back end? In our application, they're setting it on the "String" object using Spring web flows. Wouldn't it fail if the data type was double or BigDecimala at the back end?
The floating point primitives have a fixed precision, and they are not accurate. That's okay if your calculations involve approximations of reality, but this is never the case with money. You don't want to lose money or for it to appear out of nowhere. Calculations need to be accurate.
You don't actually need precision beyond whole cents, unless you're performing division operations. If you don't perform division operations, BigInteger is fine.
As soon as you receive a string from the front end, you can convert it to a BigDecimal or BigInteger using the methods and constructors of those classes. I don't know how your application is set up, I imagine that there are frameworks out there that can implicitly convert strings to the intended data type upon deserializing the request. For instance, if you're using JAX-B, you can write an adapter that will perform this conversion for you whenever you try to deserialize XML/JSON.
Prasanna Raman wrote:
Stephan van Hulst wrote:you may want to stick with what you have until you manage to convince your project lead that it's okay to replace strings with better types as you go.
By this you mean, until I manage to convince them to change it in all places consistently?
No, that will never happen if your application is already big enough. Refactoring an application is easiest and will be least expensive when you change it as you go. Whenever you discover a String that's used to store money, refactor it so it uses a different type instead. Few project leads will ever approve committing a programmer to refactoring it all at once.
But, is there a way that this conversion can be done on the front end before trying to set it on the object?
Or a long, which can store over $9×10¹⁷ if you use cents. There are new currency classes coming out with Java9, but I haven't managed to see how they work yet. So I don't know whether they will help you.
Stephan van Hulst wrote:. . . I would use a BigInteger to store money in cents. . . .
You can model money using a combination of a Currency and a BigInteger (or a long!), but for most applications the currency is implicit. It's like in order to get an actual instance of time you need a time zone, but for most applications the time zone is implicit.
Stephan van Hulst wrote:Probably not, because the front-end doesn't know what a BigDecimal is.
I am slightly confused here. Should the front end have to know what it is? If I pass in a valid number on form submit from the front end, wouldn't the value be set correctly on the BigDecimal income field that I have on my object?
Once you have got those figures into your code, put them into a database as BIGINT or DECIMAL(12,2) or similar. I have probably got the numbers wrong for DECIMAL.
If not, is everything always treated as a String then?
Paul Clapham wrote:Of course, everything sent from the front end is a string. HTTP requests are just text -- at least, they are bytes, but you can't expect to get (say) 8 bytes which represent a Java long variable directly. You're going to get some kind of text and you're going to have to convert some of that text into a numeric type.
Paul, I am confused now :( If everything is a String, do you know how the following works?
@NumberFormat(style = Style.NUMBER)
private Integer employLength;
I see this Integer field declared in our application, but there is no explicit conversion done anywhere as far as I can tell.
you should be asking somebody who knows something about your code base that question. And seriously, before you decide to start refactoring the system you should have a better knowledge of that system.
So, unless that line is taking care of the conversion, I don't understand how this works. That's why I asked.
Also, I am not trying to refactor the whole system. I am just trying to add a new income field, and I didn't want to use Strings like it's been used everywhere else in the application. Sorry for the confusion!
I'm still trying to understand how I can use it for my needs. I need my program to receive a comma separated string from the UI, strip the numbers and store it in a long or BigInteger variable. Could someone kindly help?
The "\\s*" means "any amount of whitespace." You can loop through this array without having to assign it to a variable:
The problem would be if the UI might return something like this:
Since a valid money amount might contain a comma, the value with a comma is quoted. If this is the case, I would use a third party CSV library.
So, is this OK to do? Can I receive the variable in a String in my application? I was trying to find ways for Spring to handle this conversion before even setting it to our variable (so that I can use a long type instead of String for our variable).
I might be confusing things here. Any comments are welcome!
almost all of the income related fields in our application are declared as "String"
So I would expect that you already have Spring configuration, or code, which deals with setting all of those existing fields. You should find out how that works for a start. (Asking people on this forum isn't going to help you do that; you should ask people in your organization if you don't already know.) Then once you understand that, you can work on writing configuration or code to set your new field.
Prasanna Raman wrote:Hello Paul,
Yes, all the fields are declared as String, and are converted to int or double using Integer.parseInt() before passing the fields on to the other application.
Then it should take you only a few minutes to copy the code and/or configuration of one of the other String fields and modify that to suit the new one. I don't see why this is a big problem.
Prasanna Raman wrote:Yes, all the fields are declared as String, and are converted to int or double using Integer.parseInt() before passing the fields on to the other application.
OK, well as has already been explained, that's not a good idea for currency - especially as it's already been established that you could overflow an int.
However, this is my take on it:
1. You have a String that contains a numeric amount with possible currency symbols involved.
2. Since you have no idea what they are, or whether they're leading or trailing, it would be nice to have a generic way of getting rid of them.
Unfortunately, you still have to make some assumptions. Mine would be:
1. Numbers are written using Arabic numerals, plus the characters '+', '-', ',' and '.'.
2. Those last four characters are never used for anything else (eg, a currency symbol).
3. Whitepsace is irrelevant.
And if those are reasonable assumptions, the operation to extract the "number" from a String boils down to a couple of regular expression operations, viz:and once you have your "number string", simply pass it to the relevant constructor for whatever type of number you want.
Note: That second bit (line 3) might need a bit of tweaking; and I'd probably add a third one to remove any leading or trailing '.'s or ','s - but hopefully you get the idea.
Dave Tolls wrote:
Winston Gutkowski wrote:
1. You have a String that contains a numeric amount with possible currency symbols involved.
I would question a UI that sent currency symbols to the backend as part of an amount string.
Could be valid if it's because it allows the user to enter the amount in any currency and the backend will make conversions (though I'd likely send that info separately). But, generally, no.
Dave Tolls wrote:I would question a UI that sent currency symbols to the backend as part of an amount string.
Me too. I'm simply allowing for the fact that they might be included.
You also have the (ugh) possibility of "accounting-style" values - eg, "(500.00)" meaning -500, but that's just a refinement to the method.
And of course, the best scenario is if you don't have to do it at all.