NumberFormatException occurs with different regional settings - java

I'm developing an application in Java and found this strange behaviour:
if the regional settings format is set to Hungarian (system default) via the Control Panel, I get this exception, but if I set it to an English one, it works perfectly. Also works on a virtual Mandriva where I'm developing the program in the first place.
This is the code snippet that causes the problem:
public String stattxt(){
double dt = time_avg();
double bpm = (Double.compare(dt, 0) == 0) ? 0 : msec2bpm(dt);
String s = "<html>Number of control points: " + timestamps.size() + "<br>Average dt: " +
Double.valueOf(new DecimalFormat("#.####").format(dt).toString()) + " ms<br>" +
"Average BPM: " + Double.valueOf(new DecimalFormat("#.####").format(bpm).toString()) + "<br>&nbsp</html>";
return s;
}
where both time_avg() and msec2bpm return double (not Double by any chance) values.
How could I make this work regardless to regional settings? Any help would be appreciated.

It seems like you're using
Double.valueOf(new DecimalFormat("#.####").format(dt).toString())
to round a number to 4 decimal places, but this looks like a hack to me and will fail due to regionalization settings (Hungary probably uses a decimal comma, not a decimal point.)
So, instead round doubles using something like:
rounded = Math.round(original * 10000)/10000.0;
And, if you want to create a string which is a double rounded to 4 decimal places, use String.format()
String.format("%.4f", original);

It looks like you should just skip the Double.valueOf:
public String stattxt(){
double dt = time_avg();
double bpm = (Double.compare(dt, 0) == 0) ? 0 : msec2bpm(dt);
String s = "<html>Number of control points: " + timestamps.size() + "<br>Average dt: " +
new DecimalFormat("#.####").format(dt) + " ms<br>" +
"Average BPM: " + new DecimalFormat("#.####").format(bpm) + "<br>&nbsp</html>";
return s;
}

Why are you converting String to Double and then again to String? Do it like this:
public String stattxt(){
double dt=time_avg();
double bpm=(Double.compare(dt, 0)==0)?0:msec2bpm(dt);
String s="<html>Number of control points: "+timestamps.size()+"<br>Average dt: "+
new DecimalFormat("#.####").format(dt).toString()+" ms<br>"+
"Average BPM: "+Double.valueOf(new DecimalFormat("#.####").format(bpm).toString())+"<br>&nbsp</html>";
return s;
}

Related

Checking if a String has a fraction part in Java : Locale involved

I have a String value which can either hold a Long or a Double. The String may be Locale based.
So it may hold the following values:
11
11.00
15,25 (for Locale like Denmark where the decimal part is denoted by a comma instead of dot)
I want to do something only when it is a Double; in sense that it contains a fraction value. A fraction value of "00" is also a valid case.
if(string contains fraction){
// do something
}
Given above three examples, control should go inside if for 11.00 and 15,25 but not for 11.
How can I check this?
Please keep in mind that Locale is involved. So dot and comma may have different meaning for different Locale. So simple regex to find their occurrence won't work. For e.g. 11,00 is 1100 if Locale is Australia and thus is not a double. But 11,00 is a double if Locale is a European country like Denmark or Germany.
I need to find some solution using NumberFormat but not able to work it out.
I have Locale info. So I know if the String is of which Locale. Given that, how can I find if String has a fraction or not?
EDIT: Since you've edited your question stating you know the Locale, you can use it with NumberFormat.getNumberInstance(locale).parse(strValue) in combination with a regex for the comma and thousand separator. Here a test code:
import java.text.DecimalFormatSymbols;
import java.text.NumberFormat;
import java.text.ParseException;
import java.util.Locale;
class Main{
private static final Locale DUTCH = new Locale("nl","NL");
public static void main(String[] a){
test("11", Locale.ENGLISH);
test("11", DUTCH);
System.out.println();
test("11.00", Locale.ENGLISH);
test("11.00", DUTCH);
System.out.println();
test("11,00", Locale.ENGLISH);
test("11,00", DUTCH);
System.out.println();
test("15.123", Locale.ENGLISH);
test("15.123", DUTCH);
System.out.println();
test("15,123", Locale.ENGLISH);
test("15,123", DUTCH);
System.out.println();
test("something", Locale.ENGLISH);
test("something", DUTCH);
}
static void test(String val, Locale locale){
try{
DecimalFormatSymbols symbols = new DecimalFormatSymbols(locale);
char decimalSep = symbols.getDecimalSeparator();
char thousandSep = symbols.getGroupingSeparator();
String escapedDecimalSep = decimalSep == '.' ? "\\." : decimalSep+"";
String escapedThousandSep = thousandSep == '.' ? "\\." : thousandSep+"";
String intRegex = "\\d+(" + escapedThousandSep + "\\d{3})*"; // Example ENGLISH: "\\d+(,\\d{3})*"
String doubleRegex = intRegex + escapedDecimalSep + "\\d+"; // Example ENGLISH: "\\d+(,\\d{3})*\\.\\d+"
NumberFormat format = NumberFormat.getInstance(locale);
Number number = format.parse(val);
if(val.matches(doubleRegex)){
double d = number.doubleValue();
System.out.println(val + " (in locale " + locale + ") is a double: " + d);
} else if(val.matches(intRegex)){
int i = number.intValue();
System.out.println(val + " (in locale " + locale + ") is an integer: " + i);
} else{
System.out.println("Unable to determine whether value " + val + " is an integer or double for locale " + locale);
}
} catch(ParseException ex){
System.out.println("Error occurred for value \"" + val + "\". Are you sure it's an integer or decimal?");
}
}
}
Try it online.
Here is the output:
11 (in locale en) is an integer: 11
11 (in locale nl_NL) is an integer: 11
11.00 (in locale en) is a double: 11.0
Unable to determine whether value 11.00 is an integer or double for locale nl_NL
Unable to determine whether value 11,00 is an integer or double for locale en
11,00 (in locale nl_NL) is a double: 11.0
15.123 (in locale en) is a double: 15.123
15.123 (in locale nl_NL) is an integer: 15123
15,123 (in locale en) is an integer: 15123
15,123 (in locale nl_NL) is a double: 15.123
Error occurred for value "something". Are you sure it's an integer or decimal?
Error occurred for value "something". Are you sure it's an integer or decimal?
With a regex you could do
Pattern decimalPattern = Pattern.compile("\\d+(,|\\.)\\d+{2}");
and then have
boolean isDecimal = decimalPattern.matcher(input).matches();
Regex:
\d+ one or more digits
(,|\\.) a decimal point or a comma
\d+ one or more digits again
Or you could do the splitting thing
String[] split = input.split("(,|\\.)");
boolean isDecimal = split.length > 1 && split[1].length() == 2;
You could use a loop to check if it have a comma or dot and then check with the if?
boolean IsADouble = false;
for (int i = 0; i < String.length(); i++) {
if (String.charAt(i) == ','|| String.charAt(i) == '.') {
IsADouble = true
}
}
And then you create the If to do something if its a double.
Hope it helped you :)

Set length of field padding and decimal precision at the same time

Is it possible to set length of field padding in the same line as setting the decimal precision? I want firstPlaceTime to display with 3 decimal points, like 8.250 instead of 8.25. Perhaps something like %8s%3f or %8s.3f?
System.out.format("%-10s%1s%-18s%1s%8s%1s%16s%-10s","Level " + level, "| ", firstPlaceName, "| ", firstPlaceTime + "s ", "|", timeGain + "s ahead |", " " + numberOfRunners + " runners");
This code shows an approach to building the format String as well as using the %8.3f to display a double.
public static void main(String[] args)
{
String level = "Beginning";
String firstPlaceName = "TheWinner!";
double firstPlaceTime = 180.234534D;
double timeGain = 10.2D;
int numberOfRunners = 10;
StringBuilder sb = new StringBuilder();
sb.append("Level %-10s"); //the level
sb.append("|"); //divider
sb.append("%-18s"); //name of winner
sb.append("|"); //divider
sb.append("%8.3f s "); //winning time
sb.append("|"); //divider
sb.append("%8.3f s ahead"); //time gain
sb.append("|"); //divider
sb.append("%5d runners"); // # of runners
System.out.format(sb.toString(),
level,
firstPlaceName,
firstPlaceTime,
timeGain,
numberOfRunners);
}
Output:
Level Beginning |TheWinner! | 180.235 s | 10.200 s ahead| 10 runners
Edit: to elaborate on a question in the comment. The OP indicated an attempt to use %8.3f and received a format error. firstPlaceTime is a double. However, the parameter was specified as:
...,firstPlaceTime + "s ",...
When the + "s " was provided as a parameter, it would have been converted to a String, and then passed to the .format(). As a String, it would not be a double to format via the %8.3f specification. It is part of the reason for suggesting moving the text into the format specification rather than attempting
the various String concatenations in the parameters.

"main" java.util.InputMismatchException [duplicate]

This question already has answers here:
Why am I getting InputMismatchException?
(5 answers)
Closed 6 years ago.
Whenever I try to compile it, it keeps giving me an exception:
This is my source code:
Scanner input = new Scanner(System.in);
DecimalFormat df = new DecimalFormat("#.##");
System.out.print("Gaji Pokok (x 10.000) : ");
double gaji = input.nextDouble();
System.out.print("Lama Tahun Kerja : ");
int th = input.nextInt();
System.out.print("Lama Bulan Kerja : ");
float bl = input.nextFloat();
if ( bl > 12)
{
System.out.println("Inputan bulan anda salah");
System.out.print("Masukkan kembali bulan yang benar : ");
float blnnew = input.nextFloat();
float tukar = blnnew;
bl = tukar;
}
float fak_peng;
fak_peng = Float.valueOf(df.format((th+(bl/12))*2.5));
System.out.print("Jumlah Faktor Penghargaan : " );
System.out.println(fak_peng + " %");
System.out.println("Nilai Sekarang : 1.0000000 " );
float per_mppeg;
per_mppeg = Float.valueOf(df.format(gaji*(fak_peng/100)*1));
System.out.print("Perhitungan MP Pegawai : " );
System.out.println(gaji + " x " + fak_peng + "% x " + " 1.0000000 = Rp." + (per_mppeg) + "(x 10.000)");
System.out.print("MP Perbulan : " );
System.out.println(per_mppeg + " + 100% = Rp." + (per_mppeg) + "(x 10.000)");
System.out.println("MP sekaligus 100% : ");
float peserta;
peserta = Float.valueOf(df.format(100.6650*per_mppeg));
float jd;
jd = Float.valueOf(df.format(14.4820*per_mppeg*0.8));
float anak;
anak = Float.valueOf(df.format(0.6090*per_mppeg*0.8));
float jml;
jml = Float.valueOf(df.format(peserta+jd+anak));
System.out.println(" Peserta = 100.6650 x "+ per_mppeg + " = " + peserta + "(x 10.000)");
System.out.println(" Jd/Dd = 14.4820 x "+ per_mppeg + " x 80% = " + jd + "(x 10.000)" );
System.out.println(" Anak = 0.6090 x "+ per_mppeg + " x 80% = " + anak + "(x 10.000)");
System.out.println("Jumlah Total = "+ jml);
float mpdua;
mpdua = Float.valueOf(df.format (jml*0.2)) ;
float mpdel;
mpdel = Float.valueOf(df.format(per_mppeg*0.8)) ;
System.out.println("MP Sekaligus 20% = "+ mpdua + "(x 10.000)");
System.out.println("MP sekaligus 80% = "+ mpdel + "(x 10.000)");
Your exception is not a compile-time error/exception; it is a runtime exception. It is thrown because the thing the scanner is reading cannot be converted to the type you are asking for (e.g., the next thing the scanner should read is "hello" but you are using scanner.nextInt(), as "hello" cannot be converted to an integer it will raise a InputMismatchException).
In your case the exception is raised when asking for a double. Probably you are using the wrong syntax. You should check which syntax your system uses to represent doubles. On some systems, for example, the fractional and the integer part of a double should be separated with a , and on other systems with a .. So one-half on the first type of system should be written as 0,5 but on the second as 0.5.
In Java the syntax the scanner uses is defined with a Locale instance.
You can check which-one your scanner uses with the locale() method and change it with useLocale() method.
So you should recheck what you give as input.
Besides your problem with the format of double you are creating your DecimalFormat on a discommanded way (see last quote below) and there is another line that may rise an exception ( NumberFormatException ), if you do not pay attention to the Locale instance you are using:
fak_peng = Float.valueOf(df.format((th+(bl/12))*2.5));
As you are using your own format to parse the decimal (new DecimalFormat("#.##");) the string that will be passed to the Float.valueOf method will depend on the Locale instance used to create the DecimalFormat object df (in the code sample you didn't use a specific Locale instance so your systems default Locale instance is used). But Float.valueOf expects its argument to use a specific syntax defined by The Java™ Language Specification regardless to your system as written in the Java API for Float.valueOf:
[...] where Sign, FloatingPointLiteral, HexNumeral, HexDigits, SignedInteger and FloatTypeSuffix are as defined in the lexical structure sections of The Java™ Language Specification, except that underscores are not accepted between digits. If s does not have the form of a FloatValue, then a NumberFormatException is thrown.
(The complete text was too big too include here. Follow this link or the one above to have more info about what Sign, FloatingPointLiteral, HexNumeral, HexDigits, SignedInteger, FloatTypeSuffix and FloatValue exactly represent)
If you want to change the Locale instance used in your DecimalFormat object, read the API for the DecimalFormat class.
To obtain a NumberFormat for a specific locale, including the default locale, call one of NumberFormat's factory methods, such as getInstance(). In general, do not call the DecimalFormat constructors directly, since the NumberFormat factory methods may return subclasses other than DecimalFormat.
In the API (follow link just before quote) they give an example of how you should correctly create an instance of a NumberFormat.
Good luck!

Java - If statement required to display the value as 0.00 instead of 0.0 [duplicate]

This question already has answers here:
Show padding zeros using DecimalFormat
(8 answers)
Closed 7 years ago.
I created this code to display a certain output however the output is displayed with as so:
First Class Parcel - Cost is £3.3
John Smith, 1 Downing Street, SQ13 9DD
Weight = 1.342kg.
This piece of code is the part of the output about(First Class Parcel - Cost is £3.3) However instead of displaying 3.3 I want to display 3.30.
#Override
public String toString() {
String str = "";
double cost = 0.00;
if (this.isFirstClass()){
cost = 3.30;
str = "First Class Parcel";
} else {
cost = 2.80;
str = "Second Class Parcel";
}
return str + " - Cost is £" + cost + "\n" + super.toString() + "\n";
}
This will help you :
DecimalFormat df = new DecimalFormat("#.00");
double d= 23.2;
System.out.println(df.format(d));
Use DecimalFormat. Something on the lines like following
double cost = 3.30;
DecimalFormat df = new DecimalFormat("#.00");
System.out.println("Cost is £" + df.format(cost) );
Have you tried:
String.format( "%.2f", cost);
http://docs.oracle.com/javase/7/docs/api/java/lang/String.html#format(java.lang.String,%20java.lang.Object...)

Using setText for more strings

I'm currently working on an Android app. This is my code:
FieldSolution.setText("y =","(Double.toString(m))","x + ", "(Double.toString(b))");
I'm trying to print "y = mx + b" whereas m and b are doubles. Somehow I'm getting exceptions.
Where lies my mistake?
fieldSolution.setText("y =" + Double.toString(m) + " x + " + Double.toString(b));
or simply
fieldSolution.setText("y =" + m + " x + " + b);
Aside: Use Java naming conventions for variable names
You can use String.format:
FieldSolution.setText(String.format("y = %fx + %f", m, b));
You can use modifiers on the %f format specifier to control precision and width of the output. You can also, if appropriate, supply a locale as an argument to format().

Categories

Resources