15

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?

3
  • 2
    if (cost !=null && !"".equals(cost) ) === if (!"".equals(cost)) ;) Commented Mar 31, 2011 at 12:10
  • 4
    @peter-lawrey: Incorrect. What if cost == null? They're not the same check at all. The former expression would return false, the latter would return true. Commented Mar 31, 2011 at 12:30
  • What is a NumberFormatException Commented Oct 13, 2016 at 6:47

13 Answers 13

27

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());
        }
    }
Sign up to request clarification or add additional context in comments.

6 Comments

+1: I would add e.getMessage() to the error message.
Image
Yes. The sysout is only an example. he has to do proper exception handling anyway. But I'll add it. thanks.
Image
+1: Finally a sane answer. The only thing I would change is to move a call to bookService outside the try block, as this particular exception only applies to parsing cost string.
Image
@Alexander Pogrebnyak yes that's true but I think it depends on how the OP wants its logic. He can't find a cheaper book without a cost. (btw... you have the same name as a professional soccer player in the bundesliga :D)
Should we really do this instead of a check like StringUtils.isNumeric(String) before calling parseInt(String)?
|
4

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 ...

1 Comment

Since this question is the top one when googling for NumberFormatException and your link seems to be dead, here is an alternative. NumberUtils.isNumber(). It currently still works, but is deprecated, so enjoy with a bit of caution.
2

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.)

Comments

1

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. ;-)

2 Comments

IMHO Client side validation can only be a part of the validation process, but nothing you should rely on (unless you want to open the window for all kinds of attack patterns)...
That's what I said: never trust your clients. Still, it's something that should be checked on client-side as well. Simple input validation on server-side is not very efficient. As others mentioned there are probably frameworks/ libraries which can help you with this. Maybe even the new Bean Validation (Java EE 6)? (I haven't tested it yet.)
1

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...

5 Comments

Exceptions should be used in exceptional circumstances, not for normal run-of-the-mill expected situations such as "nothing was input". Exceptions are expensive to set up.
True, but as long as we don't get out parameters in Java, you hardly get around (the regex method is faulty!). Also why would the exception be expensive to "set up"? It's only an entry in the exception table, so as long as you don't take the exceptional code path (and that should be rare) there's no real performance problem.
Think Voo is right, how else would you check this?
Sorry, what do you mean "you hardly get around"? And "get out parameters"?
"hardly get around [using the exception]" it should be. The correct regex approach would need an exhaustive list of numbers (all numbers < 10 digits ok, and then 2000000000|2000000001|..|2147483647). Out parameters would be obviously the best solution i.e. get a signature boolean tryParseInt(int val, out int erg) - see C# for one language that has this.
1

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 return false.

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]

Comments

1
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;
    }

}

Comments

0

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(); 
} 

3 Comments

To repeat myself: The regex will allow strings like "9999999999999999999999", but the parser will throw an exception. The same goes for the float regex.
@Voo: for the above code 9999999999999999999999 works fine. let me know if am wrong?
Your code does allow 9999999999999999999999 as input, which if you try to parse it in the if will throw an exception. The real problem isn't just "is this string a number?" but "Is this string a number and can be represented as an integer?".
0

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
}

3 Comments

Scanner is using Integer.parseInt internally so there is no avoiding try/catch but sweeping them under the carpet.
Interesting... I didn't think to look at the source. In Scanner.hasNext they match the string buffer against an integer pattern though, so I'm not convinced there's a way to make it actually throw an nfe, even internally. If you've checked hasNextInt(), nextInt() should be safe too.
@DanubianSailor: at least you avoid the try/catch in your code. It's nicer to deal with a boolean.
0

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());
            }
        }

}
}

Comments

-1

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

2 Comments

That's no solution! The regex will cost = "9999999999999999999999" just fine, before the parser throws the exception.
Thanks. I think the only way to get a 100% correct regex would be an exhaustive approach for the larger values, which will be extremely inefficient. So I fear we'll have to live with the bad style of "misusing" exceptions in this case until Java gets out parameters.
-1

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.

Comments

-1

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:

  1. Extract method getAsInt(String param), in it:
  2. Use String.isEmpty() (Since Java 6),
  3. 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...

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.