问题
In my day to day web application development there are many instances where we need to take some number inputs from the user.
Then pass on this number input to may be service or DAO layer of the application.
At some stage since its a number (integer or float), we need to convert it into Integer as shown in the following code snippet.
String cost = request.getParameter("cost");
if (cost !=null && !"".equals(cost) ){
Integer intCost = Integer.parseInt(cost);
List<Book> books = bookService . findBooksCheaperThan(intCost);
}
Here in the above case I have to check if the input is not null or if there is no input (blank) or sometimes there is a possibility of a non number inputs e.g. blah, test etc.
What is the best possible way of handling such situations?
回答1:
Just catch your exception and do proper exception handling:
if (cost !=null && !"".equals(cost) ){
try {
Integer intCost = Integer.parseInt(cost);
List<Book> books = bookService . findBooksCheaperThan(intCost);
} catch (NumberFormatException e) {
System.out.println("This is not a number");
System.out.println(e.getMessage());
}
}
回答2:
As always, the Jakarta Commons have at least part of the answer :
NumberUtils.isNumber()
This can be used to check most whether a given String is a number. You still have to choose what to do in case your String isnt a number ...
回答3:
Exceptions in recent versions of Java aren't expensive enough to make their avoidance important. Use the try/catch block people have suggested; if you catch the exception early in the process (i.e., right after the user has entered it) then you're not going to have the problem later in the process (because it'll be the right type anyway).
Exceptions used to be a lot more expensive than they are now; don't optimize for performance until you know the exceptions are actually causing a problem (and they won't, here.)
回答4:
I suggest to do 2 things:
- validate the input on client side before passing it to the Servlet
- catch the exception and show an error message within the user frontend as Tobiask mentioned. This case should normally not happen, but never trust your clients. ;-)
回答5:
one posibility: catch the exception and show an error message within the user frontend.
edit: add an listener to the field within the gui and check the user inputs there too, with this solution the exception case should be very rare...
回答6:
Documentation for the method from the Apache Commons Lang (from here):
Checks whether the String a valid Java number.
Valid numbers include hexadecimal marked with the 0x qualifier, scientific notation and numbers marked with a type qualifier (e.g. 123L).
Null
and empty String will returnfalse
.Parameters:
`str` - the `String` to check
Returns:
`true` if the string is a correctly formatted number
isNumber
from java.org.apache.commons.lang3.math.NumberUtils:
public static boolean isNumber(final String str) {
if (StringUtils.isEmpty(str)) {
return false;
}
final char[] chars = str.toCharArray();
int sz = chars.length;
boolean hasExp = false;
boolean hasDecPoint = false;
boolean allowSigns = false;
boolean foundDigit = false;
// deal with any possible sign up front
final int start = (chars[0] == '-') ? 1 : 0;
if (sz > start + 1 && chars[start] == '0' && chars[start + 1] == 'x') {
int i = start + 2;
if (i == sz) {
return false; // str == "0x"
}
// checking hex (it can't be anything else)
for (; i < chars.length; i++) {
if ((chars[i] < '0' || chars[i] > '9')
&& (chars[i] < 'a' || chars[i] > 'f')
&& (chars[i] < 'A' || chars[i] > 'F')) {
return false;
}
}
return true;
}
sz--; // don't want to loop to the last char, check it afterwords
// for type qualifiers
int i = start;
// loop to the next to last char or to the last char if we need another digit to
// make a valid number (e.g. chars[0..5] = "1234E")
while (i < sz || (i < sz + 1 && allowSigns && !foundDigit)) {
if (chars[i] >= '0' && chars[i] <= '9') {
foundDigit = true;
allowSigns = false;
} else if (chars[i] == '.') {
if (hasDecPoint || hasExp) {
// two decimal points or dec in exponent
return false;
}
hasDecPoint = true;
} else if (chars[i] == 'e' || chars[i] == 'E') {
// we've already taken care of hex.
if (hasExp) {
// two E's
return false;
}
if (!foundDigit) {
return false;
}
hasExp = true;
allowSigns = true;
} else if (chars[i] == '+' || chars[i] == '-') {
if (!allowSigns) {
return false;
}
allowSigns = false;
foundDigit = false; // we need a digit after the E
} else {
return false;
}
i++;
}
if (i < chars.length) {
if (chars[i] >= '0' && chars[i] <= '9') {
// no type qualifier, OK
return true;
}
if (chars[i] == 'e' || chars[i] == 'E') {
// can't have an E at the last byte
return false;
}
if (chars[i] == '.') {
if (hasDecPoint || hasExp) {
// two decimal points or dec in exponent
return false;
}
// single trailing decimal point after non-exponent is ok
return foundDigit;
}
if (!allowSigns
&& (chars[i] == 'd'
|| chars[i] == 'D'
|| chars[i] == 'f'
|| chars[i] == 'F')) {
return foundDigit;
}
if (chars[i] == 'l'
|| chars[i] == 'L') {
// not allowing L with an exponent or decimal point
return foundDigit && !hasExp && !hasDecPoint;
}
// last character is illegal
return false;
}
// allowSigns is true iff the val ends in 'E'
// found digit it to make sure weird stuff like '.' and '1E-' doesn't pass
return !allowSigns && foundDigit;
}
[code is under version 2 of the Apache License]
回答7:
public class Main {
public static void main(String[] args) {
String number;
while(true){
try{
number = JOptionPane.showInputDialog(null);
if( Main.isNumber(number) )
break;
}catch(NumberFormatException e){
System.out.println(e.getMessage());
}
}
System.out.println("Your number is " + number);
}
public static boolean isNumber(Object o){
boolean isNumber = true;
for( byte b : o.toString().getBytes() ){
char c = (char)b;
if(!Character.isDigit(c))
isNumber = false;
}
return isNumber;
}
}
回答8:
To Determine if a string is Int or Float and to represent in longer format.
Integer
String cost=Long.MAX_VALUE+"";
if (isNumeric (cost)) // returns false for non numeric
{
BigInteger bi = new BigInteger(cost);
}
public static boolean isNumeric(String str)
{
NumberFormat formatter = NumberFormat.getInstance();
ParsePosition pos = new ParsePosition(0);
formatter.parse(str, pos);
return str.length() == pos.getIndex();
}
回答9:
You can avoid the unpleasant looking try/catch or regex by using the Scanner class:
String input = "123";
Scanner sc = new Scanner(input);
if (sc.hasNextInt())
System.out.println("an int: " + sc.nextInt());
else {
//handle the bad input
}
回答10:
Try to convert Prize into decimal format...
import java.math.BigDecimal;
import java.math.RoundingMode;
public class Bigdecimal {
public static boolean isEmpty (String st) {
return st == null || st.length() < 1;
}
public static BigDecimal bigDecimalFormat(String Preis){
//MathContext mi = new MathContext(2);
BigDecimal bd = new BigDecimal(0.00);
bd = new BigDecimal(Preis);
return bd.setScale(2, RoundingMode.HALF_UP);
}
public static void main(String[] args) {
String cost = "12.12";
if (!isEmpty(cost) ){
try {
BigDecimal intCost = bigDecimalFormat(cost);
System.out.println(intCost);
List<Book> books = bookService.findBooksCheaperThan(intCost);
} catch (NumberFormatException e) {
System.out.println("This is not a number");
System.out.println(e.getMessage());
}
}
}
}
回答11:
I don't know about the runtime disadvantages about the following but you could run a regexp match on your string to make sure it is a number before trying to parse it, thus
cost.matches("-?\\d+\\.?\\d+")
for a float
and
cost.matches("-?\\d+")
for an integer
EDIT
please notices @Voo's comment about max int
回答12:
In Java there's sadly no way you can avoid using the parseInt function and just catching the exception. Well you could theoretically write your own parser that checks if it's a number, but then you don't need parseInt at all anymore.
The regex method is problematic because nothing stops somebody from including a number > INTEGER.MAX_VALUE which will pass the regex test but still fail.
回答13:
That depends on your environment. JSF for example would take the burden of manually checking and converting Strings <-> Numbers from you, Bean Validation is another option.
What you can do immediately in the snippet you provide:
- Extract method
getAsInt(String param)
, in it: - Use
String.isEmpty()
(Since Java 6), - surround with
try / catch
What you should definitely think about if you happen to write a lot of code like this:
public void myBusinessMethod(@ValidNumber String numberInput) {
// ...
}
(This would be interceptor-based).
Last but not least: Save the work and try to switch to a framework which gives you support for these common tasks...
来源:https://stackoverflow.com/questions/5499523/how-to-avoid-number-format-exception-in-java