0

Given:

Locale userLocale = Locale.forLanguageTag("uk-UK");
DecimalFormat decimalFormat = (DecimalFormat) NumberFormat.getInstance(userLocale);
decimalFormat.setParseBigDecimal(true);
System.out.println(decimalFormat.parse("123456,99").toString()); // output: 123456.99 -> it's OK
System.out.println(decimalFormat.parse("123456Test99").toString()); // output: 123456 -> it's BAD

Expected:

ParseException on last input.

  1. Why not fail fast check was chosen by jdk's developers?
  2. How do you handle such cases?

My current attempt:

import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.text.ParseException;
import java.util.Locale;
import static java.lang.Character.isDigit;

private BigDecimal processNumber(DecimalFormat numberFormat, String rowValue) throws ParseException {
    BigDecimal value = null;
    if (rowValue == null) return null;
    final char groupingSeparator = numberFormat.getDecimalFormatSymbols().getGroupingSeparator();
    final char decimalSeparator = numberFormat.getDecimalFormatSymbols().getDecimalSeparator();
    final char minusSign = numberFormat.getDecimalFormatSymbols().getMinusSign();
    for (char ch : rowValue.toCharArray())
        if (!isDigit(ch) && ch != decimalSeparator && ch != groupingSeparator && ch != minusSign)
            throw new ParseException("", 0); // wrong pos, I know, but it's excessively here
    if (!rowValue.isEmpty())
        value = new BigDecimal(numberFormat.parse(rowValue).toString());
    return value;
}
Woland
  • 623
  • 2
  • 13
  • 31
  • Have you tried to use `parse(String, ParsePosition)`? I only just did a quick read, but it seems `ParsePosition` will indicate at which position the parsing ended. If this end position is before the end of the provided string, not the whole string was parsed and you may treat that as an error. – Roger Gustavsson Oct 09 '19 at 14:11
  • *"Why not fail fast check was chosen by jdk's developers?"* - We are not them, so we can't tell you why *they* decided to design it this way. My guess was that they wanted to support partial parses because it is *useful* for a lot of people. Either way, clearly it is not an oversight. – Stephen C Oct 10 '19 at 07:52
  • @StephenC yes, I asked to get opinions, maybe I miss smth and that is a good designed api. But for me that way is error prone... – Woland Oct 10 '19 at 13:26
  • @StephenC I mean smth like that https://stackoverflow.com/a/45632988/4386227 – Woland Oct 10 '19 at 13:36
  • @Woland - Questions that are asking for opinion-based answers are off-topic on StackOverflow; see https://stackoverflow.com/help/on-topic. If you want a discussion, try Quora. (I do know what "failfast" means.) – Stephen C Oct 10 '19 at 14:40

1 Answers1

1

The following is an example where I have used ParsePosition to find out where the parsing ended. If not the whole input string was parsed, an error is printed.

String string1 = "123456,99";
String string2 = "123456Test99";

Locale userLocale = Locale.forLanguageTag("uk-UK");
DecimalFormat decimalFormat = (DecimalFormat) NumberFormat.getInstance(userLocale);
decimalFormat.setParseBigDecimal(true);

ParsePosition parsePosition = new ParsePosition(0);
Number number1 = decimalFormat.parse(string1, parsePosition);

if (parsePosition.getIndex() <= string1.length()) {
  System.out.println("Parse error");
} else {
  System.out.println(number1.toString());
}

parsePosition = new ParsePosition(0);
Number number2 = decimalFormat.parse(string2, parsePosition);

if (parsePosition.getIndex() <= string2.length()) {
  System.out.println("Parse error");
} else {
  System.out.println(number2.toString());
}

Generated output:

123456.99
Parse error
Roger Gustavsson
  • 1,689
  • 10
  • 20