前几天线上一个功能莫名其妙没有正常执行,而且奇怪的这个功能模块以及很久没有改动了,而且一直运行的好好的,从没出问题,今天排查看日志,发现是程序在进行一段内存排序时,抛NumberFormatException了。
Exception in thread "main" java.lang.NumberFormatException: For input string: "30d"
这我就纠结了,因为内存排序是通过把从数据库去取出来的String转化成BigDecimal来进行排序的,而且NumberFormatException就是抛在这句代码上:
BigDecimal bg = new BigDecimal(answer);
因为answer是从DB里取出来的,这个answer是用户通过页面提交的,而且在存到DB之前,一个同事专门写了个方法来判断用户提交的答案是不是能转换成数字,如果不能转换成数字,则会拒绝用户的这次提交。既然已经过滤掉了非法的答案,那为什么还会把30d存入到DB呢?
因此,我去看过滤掉非法答案的非法是如何来过滤的?
try{
Float floatAnswer = Float.valueOf(answer);
}catch (NumberFormatException e) {
// TODO: handle exception
}
如果上述代码没有抛出异常,就认为输入的答案在格式上时合法的。一看到这个Float.valueOf(answer),我就知道问题是出在这里了, Float.valueOf(answer)和new BigDecimal(answer)在判断是一个string能否正确转换成数字上采取的是不同的标准,先来看一下Float.value(String s)方法:
public static Float valueOf(String s) throws NumberFormatException {
return new Float(FloatingDecimal.readJavaFormatString(s).floatValue());
}
FloatingDecimal.readJavaFormatString(s)方法是sun.misc.FloatingDecimal里面,这个类下载open jdk的源码后可以看到,通过截取readJavaFormatString方法的一段代码就可以知道为什么30d这个数字会通过校验被存进DB了
if ( i < l &&
((i != l - 1) ||
(in.charAt(i) != 'f' &&
in.charAt(i) != 'F' &&
in.charAt(i) != 'd' &&
in.charAt(i) != 'D'))) {
break parseNumber; // go throw exception
上述代码段可以看出,数字后面加上字母D、d、F、f是合法的。
而BigDecimal(String val)在进行校验的时候,则不允许字母出现在最后,但这样的字符串"2e9"是合法的,因为可以理解成科学计算法,因为代码过长,所以就不具体分析了。
至此,这个诡异的NumberFormatException已经分析清楚了,虽然问题的原因已经弄清楚了,但我认为从这个问题中可以总结出两点:
1.对于一些常用API方法,需要彻底弄清出原理,如果实在不清楚其具体原理,也需要用一些边界值去测试
2.对于任何参数,如果该参数使用的时候存在某种风险,那都要采取怀疑态度,不要因为某些地方已经对这个参数做过校验了就完全相信(就像上面的例子里的情况)
一点小总结,
分享到:
相关推荐
在Java编程中,`java.lang.NumberFormatException`是一个常见的运行时异常,它通常发生在尝试将一个字符串转换为数值类型(如int、long、float或double)时,但该字符串无法被解析为有效的数值。"For input string: ...
NumberFormatException如何解决.md
NumberFormatException解决办法.md
Java.lang.NumberFormatException错误是Java中的一种常见异常,主要是因为将非数字类型的数据强制转换为数字类型时引发的。例如,将String类型的数据强制转换为Integer类型时,如果该String类型的数据不符合数字格式...
NumberFormatException(解决方案).md
在Java编程语言中,`NumberFormatException`是一个常见的运行时异常,它发生在尝试将字符串转换为特定数字类型(如`Integer`, `Double`, `Float`等)时,如果字符串不能被解析为对应类型的数值,就会抛出这个异常。...
在上述代码中,我们尝试用`parseInt()`方法转换字符串,如果失败,则捕获`NumberFormatException`并抛出一个自定义的`IllegalArgumentException`,附带有关于问题的详细信息。 然而,我们还需要考虑另一种异常情况...
项目中碰到的,记录一下
项目中碰到的,已解决,写个文档记录一下
然而,如果用户输入的不是一个有效的整数,`parseInt`方法会抛出一个`NumberFormatException`。因此,我们使用`try-catch`块来处理这个可能的异常。当捕获到`NumberFormatException`时,我们会打印一条错误信息,...
在.NET编程环境中,NetBeans 6.8是一个流行的开源集成开发环境(IDE),它支持多种语言,包括Java、C++和Groovy等。利用NetBeans 6.8创建一个计算器项目是一个很好的学习实践,可以让你熟悉GUI编程和事件处理。下面...
在Java编程中,创建一个图形用户界面(GUI)计算器是一个常见的练习,可以帮助初学者理解事件处理和异常处理的概念。在这个“java加减乘除计算器界面编程”项目中,我们需要实现一个简单的计算器应用,具备加、减、...
开发者会创建一个`Random`对象,然后调用其`nextInt(int bound)`方法生成一个指定范围内的随机整数。例如,如果设定范围为1到100,代码可能如下: ```java Random rand = new Random(); int secretNumber = ...
在编程领域,判断一个字符串或字符串中的一个字符是否为数字类型是常见的操作,尤其是在处理用户输入、数据分析或者格式验证时。下面将详细讲解几种不同语言中实现这一功能的方法,以及如何确保判断的安全性和效率。...