A friend of mine recently noticed that the good old DecimalFormat class is "broken". If you try to parse a string that is not a number but is starting with a number, the DecimalFormat.parse will return what it managed to parse.
The correct behavior should be to throw a parse exception IMHO. Judging from an old post in the Sun bug tracker, The folks at Sun don't think it really is, they call the default mode of parsing the "lenient" mode. It accepts bad inputs. Then why throwing ParseException at all and why not return 0/NaN when the first character is not a number? Why accepting 1toto2 as a number and not toto2?
In reality it can really create unexpected problems. For example, in France, 0.1 is 0,1 because of the Locale conventions. If a user enters 0.1 in a French Locale, a method using DecimalFormat.parse will interpret it as 0 without throwing any exception.
Note that DateFormat does not have that problem, at one point Sun added setLenient flag to be able to be in non Lenient mode. It would be very simple to do it with DecimalFormat, I did it myself as an exercise. In DecimalFormat.subparse, the 2 last break statements should stop processing in lenient mode. Lines 1528 to 1531:
sawExponent = true;
}
break; // Whether we fail or succeed, we exit this loop
}
else {
break;
}
become:
sawExponent = true;
} else {
if (isLenient()) {
parsePosition.index = oldStart;
parsePosition.index = oldStart;
return false;
}
}
break; // we succeed, we exit this loop
}
else {
if (isLenient()) {
parsePosition.index = oldStart;
parsePosition.errorIndex = oldStart;
return false;
}
break;
}
Wednesday, May 14, 2008
DecimalFormat Is Broken
A friend of mine recently noticed that the good old DecimalFormat class is "broken". If you try to parse a string that is not a number but is starting with a number, the DecimalFormat.parse will return what it managed to parse.
The correct behavior should be to throw a parse exception IMHO. Judging from an old post in the Sun bug tracker, The folks at Sun don't think it really is, they call the default mode of parsing the "lenient" mode. It accepts bad inputs. Then why throwing ParseException at all and why not return 0/NaN when the first character is not a number? Why accepting 1toto2 as a number and not toto2?
In reality it can really create unexpected problems. For example, in France, 0.1 is 0,1 because of the Locale conventions. If a user enters 0.1 in a French Locale, a method using DecimalFormat.parse will interpret it as 0 without throwing any exception.
Note that DateFormat does not have that problem, at one point Sun added setLenient flag to be able to be in non Lenient mode. It would be very simple to do it with DecimalFormat, I did it myself as an exercise. In DecimalFormat.subparse, the 2 last break statements should stop processing in lenient mode. Lines 1528 to 1531:
sawExponent = true;
}
break; // Whether we fail or succeed, we exit this loop
}
else {
break;
}
become:
sawExponent = true;
} else {
if (isLenient()) {
parsePosition.index = oldStart;
parsePosition.index = oldStart;
return false;
}
}
break; // we succeed, we exit this loop
}
else {
if (isLenient()) {
parsePosition.index = oldStart;
parsePosition.errorIndex = oldStart;
return false;
}
break;
}
The correct behavior should be to throw a parse exception IMHO. Judging from an old post in the Sun bug tracker, The folks at Sun don't think it really is, they call the default mode of parsing the "lenient" mode. It accepts bad inputs. Then why throwing ParseException at all and why not return 0/NaN when the first character is not a number? Why accepting 1toto2 as a number and not toto2?
In reality it can really create unexpected problems. For example, in France, 0.1 is 0,1 because of the Locale conventions. If a user enters 0.1 in a French Locale, a method using DecimalFormat.parse will interpret it as 0 without throwing any exception.
Note that DateFormat does not have that problem, at one point Sun added setLenient flag to be able to be in non Lenient mode. It would be very simple to do it with DecimalFormat, I did it myself as an exercise. In DecimalFormat.subparse, the 2 last break statements should stop processing in lenient mode. Lines 1528 to 1531:
sawExponent = true;
}
break; // Whether we fail or succeed, we exit this loop
}
else {
break;
}
become:
sawExponent = true;
} else {
if (isLenient()) {
parsePosition.index = oldStart;
parsePosition.index = oldStart;
return false;
}
}
break; // we succeed, we exit this loop
}
else {
if (isLenient()) {
parsePosition.index = oldStart;
parsePosition.errorIndex = oldStart;
return false;
}
break;
}
Tuesday, April 29, 2008
Using MiG Layout For Better Swing Development
I have forgotten a few libraries in my Better Swing Development article, and notably MiGLayout.
GridBagLayout is too verbose, and still feels too clumsy. This is why a while back I wrote a small tool to help visualize various GridBagLayouts for people who are not used to it. But it would have been much simpler to use a better layout instead.
MiGLayout is good, I managed to have good results without almost any practices on not so simple layouts. It also makes the code more concise.
Related to my previous post about SwiXml, and as SwiXml does not yet support MiGLayout, I was thinking how easy it would be to achieve something relatively similar. With proper code conventions it is quite easy to describe the GUI outside a Java file, for example, for an easy start in a Beanshell file.
The beanshell file would contain components construction, and MiGLayout of them afterwards, that's it. All listeners and component behaviours would be kept in java classes. With this kind of code split. The beanshell file is then extremely simple, as simple as the SwiXml.
MiGLayout also has plenty of extra functionalities like "hidemode 1" that can help automatically redoing the layout if a component becomes visible/invisible.
GridBagLayout is too verbose, and still feels too clumsy. This is why a while back I wrote a small tool to help visualize various GridBagLayouts for people who are not used to it. But it would have been much simpler to use a better layout instead.
MiGLayout is good, I managed to have good results without almost any practices on not so simple layouts. It also makes the code more concise.
Related to my previous post about SwiXml, and as SwiXml does not yet support MiGLayout, I was thinking how easy it would be to achieve something relatively similar. With proper code conventions it is quite easy to describe the GUI outside a Java file, for example, for an easy start in a Beanshell file.
The beanshell file would contain components construction, and MiGLayout of them afterwards, that's it. All listeners and component behaviours would be kept in java classes. With this kind of code split. The beanshell file is then extremely simple, as simple as the SwiXml.
MiGLayout also has plenty of extra functionalities like "hidemode 1" that can help automatically redoing the layout if a component becomes visible/invisible.
Subscribe to:
Posts
(
Atom
)