如何避免java中的数字格式exception?

在我的日常Web应用程序开发中,有许多情况需要从用户那里获取一些数字输入。

然后传递此数字输入可以是应用程序的服务或DAO层。

在某个阶段,因为它是一个数字(整数或浮点数),我们需要将它转换为Integer,如下面的代码片段所示。

String cost = request.getParameter("cost"); if (cost !=null && !"".equals(cost) ){ Integer intCost = Integer.parseInt(cost); List books = bookService . findBooksCheaperThan(intCost); } 

在上面的例子中,我必须检查输入是否为空或者是否没有输入(空白),或者有时可能存在非数字输入,例如,等等,测试等。

处理此类情况的最佳方法是什么?

抓住您的exception并进行适当的exception处理:

 if (cost !=null && !"".equals(cost) ){ try { Integer intCost = Integer.parseInt(cost); List books = bookService . findBooksCheaperThan(intCost); } catch (NumberFormatException e) { System.out.println("This is not a number"); System.out.println(e.getMessage()); } } 

与往常一样,雅加达下议院至少有部分答案:

NumberUtils.isNumber()

这可用于检查给定String是否为数字。 你仍然必须选择做什么,以防你的字符串不是一个数字…

最近版本的Java中的exception并不足以使其避免变得非常重要。 使用人们建议的try / catch块; 如果你在过程的早期就捕获了exception(即,在用户输入之后),那么你将不会在此过程中遇到问题(因为它无论如何都是正确的类型)。

以前的例外费用比现在贵很多; 在您知道exception实际导致问题之前不要优化性能(在这里它们不会。)

一个可能性:捕获exception并在用户前端显示错误消息。

编辑:在gui中的字段中添加一个监听器,并检查用户输入,使用此解决方案,exception情况应该非常罕见……

来自Apache Commons Lang的方法文档( 从这里 ):

检查String是否为有效的Java编号。

有效数字包括用0x限定符标记的hex,科学记数法和用类型限定符标记的数字(例如123L)。

Null和空String将返回false

参数:

 `str` - the `String` to check 

返回:

 `true` if the string is a correctly formatted number 

来自java.org.apache.commons.lang3.math.NumberUtils的isNumber :

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

[代码在Apache许可证的第2版下]

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

我建议做两件事:

  • 在将其传递给Servlet之前validation客户端的输入
  • 捕获exception并在Tobiask提到的用户前端内显示错误消息。 这种情况通常不会发生,但绝不相信您的客户。 😉

确定字符串是Int还是Float并以更长的格式表示。

整数

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

您可以使用Scanner类来避免令人不快的try / catch或regex:

 String input = "123"; Scanner sc = new Scanner(input); if (sc.hasNextInt()) System.out.println("an int: " + sc.nextInt()); else { //handle the bad input } 

尝试将奖品转换为十进制格式……

 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 books = bookService.findBooksCheaperThan(intCost); } catch (NumberFormatException e) { System.out.println("This is not a number"); System.out.println(e.getMessage()); } } } } 

我不知道有关以下内容的运行时缺点,但您可以在字符串上运行regexp匹配,以确保它在尝试解析之前是一个数字,因此

 cost.matches("-?\\d+\\.?\\d+") 

浮动

 cost.matches("-?\\d+") 

为整数

编辑

请注意@Voo关于max int的评论

在Java中,遗憾的是你无法避免使用parseInt函数并且只是捕获exception。 那么理论上你可以编写自己的解析器来检查它是否是一个数字,但是你根本就不需要parseInt了。

正则表达式方法是有问题的,因为没有什么能阻止某人包含一个数字> INTEGER.MAX_VALUE,它将通过正则表达式测试但仍然失败。

这取决于您的环境。 例如,JSF将负担手动检查和转换字符串< - >数字的负担,Beanvalidation是另一种选择。

您可以在您提供的代码段中立即执行的操作:

  1. 提取方法getAsInt(String param) ,其中:
  2. 使用String.isEmpty() (自Java 6开始 ),
  3. try / catch环绕

如果你碰巧写了很多这样的代码,你应该考虑一下:

 public void myBusinessMethod(@ValidNumber String numberInput) { // ... } 

(这将是基于拦截器的)。

最后但并非最不重要的:保存工作并尝试切换到一个框架,为您提供对这些常见任务的支持……