0

Here is my code:

  private double stripCurrency(String sBudget) {

    DecimalFormat formatter = (DecimalFormat) NumberFormat.getCurrencyInstance(Locale.US);
    DecimalFormatSymbols symbols = formatter.getDecimalFormatSymbols();
    symbols.setCurrencySymbol("");
    formatter.setDecimalFormatSymbols(symbols);
    double d = Double.valueOf(formatter.format(sBudget)); // Line 52 in LogCat
    return d;
  }

Here is LogCat:

09-16 10:12:07.641: E/AndroidRuntime(1463):     at java.text.NumberFormat.format(NumberFormat.java:304)
09-16 10:12:07.641: E/AndroidRuntime(1463):     at java.text.DecimalFormat.format(DecimalFormat.java:702)
09-16 10:12:07.641: E/AndroidRuntime(1463):     at java.text.Format.format(Format.java:93)
09-16 10:12:07.641: E/AndroidRuntime(1463):     at com.---.---.GasUtil.stripCurrency(GasUtil.java:52)

This happens when opening app for the first time. The passed in String is the SharedPreference default of "100".

What I am trying to do:

There should be a String stored in SharedPreferences and I convert that to a double. An older version of the app allowed for currency symbols in the String. So I am trying to sanitize from that old way. So I am formatting it to strip out old currency symbols and turning into a double. Not sure if my above code is the best way to do that, even after I resolve this bug, or if there is a better way? So I need to sanitize in a way that will handle both correct and bad formatting.

TheLettuceMaster
  • 15,594
  • 48
  • 153
  • 259
  • is the currency symbol known before hande? is the value stored in the String always a double, but sometimes with a '$'? like would "4.00","$4.00","$1.00" all be possible valid values? – Dave Sep 16 '14 at 17:24
  • Just don't remove the currency symbol from the format. Why did you do it in the first place? Were you worried that a "$" would creep into a `double`? – Ordous Sep 16 '14 at 17:25
  • @Ordous I use the variable in calculations. So I decided to ONLY show currency when an item is about to be displayed. @Dave It could be 100, 100.00 or $100. I simply want to take either one and covert it to a `double` (or `BigDecimal` -- but these are basic, basic calculations). – TheLettuceMaster Sep 16 '14 at 17:38
  • @KickingLettuce That doesn't answer my question. Why did you remove the currency symbol from the `DecimalFormat` object? Your output won't have the currency sign anyway *since it's a `double`, not a `String`* – Ordous Sep 16 '14 at 17:43
  • I thought it was a good way to strip out any currency sign so it formats safely from string to double. I got the idea from another question here. – TheLettuceMaster Sep 16 '14 at 17:45
  • [Dont use `double` for currency](https://stackoverflow.com/questions/3730019/why-not-use-double-or-float-to-represent-currency). – Raedwald Sep 20 '19 at 09:30

1 Answers1

3

formatter.format(sBudget) does take an Object, but it checks if it is any form of a Number otherwise it throws IllegalArgumentException. Look at the source code DecimalFormat.

Here is the corrected way of converting a currency string back to double.

private static double stripCurrency(String sBudget) {
        //to handle strings with no dollar sign.
        if(sBudget.trim().charAt(0) != '$') {
            sBudget = "$"+sBudget;
        }
        DecimalFormat formatter = (DecimalFormat) NumberFormat.getCurrencyInstance(Locale.US);
        Number parse = null;
        try {
            parse = formatter.parse(sBudget);
            System.out.println(parse);
        } catch (ParseException e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
        return parse.doubleValue();
    }

Here is the source code for the root cause of the exception you are facing. When we call formatter.format(sBudget), the call end up with the following method in DecimalForamt.

public final StringBuffer format(Object number,
                                     StringBuffer toAppendTo,
                                     FieldPosition pos) {
        if (number instanceof Long || number instanceof Integer ||
                   number instanceof Short || number instanceof Byte ||
                   number instanceof AtomicInteger ||
                   number instanceof AtomicLong ||
                   (number instanceof BigInteger &&
                    ((BigInteger)number).bitLength () < 64)) {
            return format(((Number)number).longValue(), toAppendTo, pos);
        } else if (number instanceof BigDecimal) {
            return format((BigDecimal)number, toAppendTo, pos);
        } else if (number instanceof BigInteger) {
            return format((BigInteger)number, toAppendTo, pos);
        } else if (number instanceof Number) {
            return format(((Number)number).doubleValue(), toAppendTo, pos);
        } else {
            throw new IllegalArgumentException("Cannot format given Object as a Number");
        }
    }
RP-
  • 5,827
  • 2
  • 27
  • 46
  • Thank you! I actually dealt with this in the past and used `Number`. Marking as correct. – TheLettuceMaster Sep 16 '14 at 18:45
  • Ok, I ran into one issue first; and I had a feeling this would happen. `Unparseable number "100.00"`. I remember `Number` failing if it was NOT a currency and it just did that. I need in my code, to work if it is currency for not. As I mentioned above, the number being passed in, may look like `100.00` or `$100.` – TheLettuceMaster Sep 16 '14 at 18:48
  • I see the problem, I thought you always have `$`. One dirty work around would be adding `$` at the beginning if one is not there. – RP- Sep 16 '14 at 19:04
  • Is it possible to do a type check? Check if String can be converted to Double, if not, convert it to number first? – TheLettuceMaster Sep 16 '14 at 19:30
  • 1
    We can do that by `try { Double.parseDouble(sBudget);} catch(NumberFormatException e) { }` catching the `NumberFormatException`. If it throws NumberFormatException, you are sure that the string can not format because of having some alphabetics or null – RP- Sep 16 '14 at 19:31
  • I tried your last suggestion and it seems to work fine! – TheLettuceMaster Sep 17 '14 at 21:04