使用 DecimalFormat 进行格式化会引发异常 - “无法将给定对象格式化为数字”
Posted
技术标签:
【中文标题】使用 DecimalFormat 进行格式化会引发异常 - “无法将给定对象格式化为数字”【英文标题】:Formatting using DecimalFormat throws exception - "Cannot format given Object as a Number" 【发布时间】:2017-07-24 06:44:41 【问题描述】:这可能看起来像是一个重复的问题,但我尝试了以下所有链接,但无法得到正确答案。
Cannot format given Object as a Number ComboBox
Illegal Argument Exception
但我不明白出了什么问题。这是我的代码
DecimalFormat twoDForm = new DecimalFormat("#.##");
double externalmark = 1.86;
double internalmark = 4.0;
System.out.println(String.valueOf((externalmark*3+internalmark*1)/4));
String val = String.valueOf((externalmark*3+internalmark*1)/4);
String wgpa1=twoDForm.format(val); // gives exception
String wgpa2=twoDForm.format((externalmark*3+internalmark*1)/4)); // works fine
System.out.println(wgpa1);
format
方法采用 Object 类型参数,这就是为什么我传递了一个 String 对象,它给出了异常
线程“main”java.lang.IllegalArgumentException 中的异常:不能 将给定的对象格式化为数字。
但是当我给双值作为参数时,程序运行良好。但是,如果该方法是使用 Object
类型参数定义的,为什么我在传递 String
时遇到异常,而在传递 double
时没有遇到异常?
【问题讨论】:
【参考方案1】:DecimalFormat
的format()
方法被重载。
在工作情况下,您正在调用:
public final String format(double number)
在失败的情况下,您正在调用:
public final String format (Object obj)
第一种方法采用一个非常具体的参数。它需要double
。
第二种情况不是这样,它接受的类型非常广泛:Object
,因此在运行时对传递的类型进行检查。
通过提供不是double
而是String
的参数,调用的方法是第二个。
在底层,此方法依赖于 format(Object number, StringBuffer toAppendTo, FieldPosition pos)
方法,该方法期望 number
参数是 Number
类的实例(Short
、Long
、...Double
) :
@Override
public final StringBuffer format(Object number,
StringBuffer toAppendTo,
FieldPosition pos)
if (number instanceof Long ||
number instanceof Integer ||
number instanceof Short ||
number instanceof Byte ||
number instanceof AtomicInteger ||
number instanceof AtomicLong ||
(number instanceof BigInteger && ((BigInteger)number).bitLength () < 64))
return format(((Number)number).longValue(), toAppendTo, pos);
else if (number instanceof BigDecimal)
return format((BigDecimal)number, toAppendTo, pos);
else if (number instanceof BigInteger)
return format((BigInteger)number, toAppendTo, pos);
else if (number instanceof Number)
return format(((Number)number).doubleValue(), toAppendTo, pos);
else
throw new IllegalArgumentException("Cannot format given Object as a Number");
但情况并非如此,因为您将 String
实例传递给它。
要解决此问题,请在成功案例中传递double
原语,或者将String
转换为Number
的实例,例如Double
和Double.valueOf(yourString)
。
我建议第一种方式(传递double
),因为它在您的代码中已经使用double
原语更自然。
第二个需要额外的从String
到Double
的转换操作。
【讨论】:
你好 YCF !我开始变得更好了!太好了。你好吗? :) 最后一次非常高兴:)【参考方案2】:如果有任何数学计算,那么使用 java.math.BigDecimal 类的方法是更好的选择,以确保结果的准确性和效率,即使数字太大。 使用 java.math.BigDecimal 代码:
double externalmark1 = 1.86;
double internalmark2 = 4.0;
System.out.println(String.valueOf((externalmark1*3+internalmark2*1)/4));
System.out.println("------------------------");
BigDecimal decimalValue1 = new BigDecimal((externalmark1*3+internalmark2*1)/4).setScale(2, RoundingMode.HALF_UP);
System.out.println("aggregatemark [direct decimalValue]: "+decimalValue1.toString());
System.out.println("------------------------");
double aggregatemark = (externalmark1*3+internalmark2*1)/4;
System.out.println("aggregatemark [double]: "+aggregatemark);
BigDecimal decimalValue2 = new BigDecimal(aggregatemark).setScale(2, RoundingMode.HALF_UP);
System.out.println("aggregatemark [decimalValue]: "+decimalValue2.toString());
System.out.println("------------------------");
String aggregatemarkStr = String.valueOf((externalmark1*3+internalmark2*1)/4);
System.out.println("aggregatemark [string] : "+aggregatemarkStr);
BigDecimal decimalValue3 = new BigDecimal(aggregatemarkStr).setScale(2, RoundingMode.HALF_UP);
System.out.println("aggregatemark [decimalValue]: "+decimalValue3.toString());
【讨论】:
【参考方案3】:答案在javadoc。它清楚地说,“数字可以是 Number 的任何子类”,并说它抛出 IllegalArgumentException
“如果 number 为 null 或不是 Number 的实例。”
(那么他们为什么不直接将参数设为 Number
类型?因为该类是抽象 Format
类的子类,不限于数字格式。显然,期望是这样一般的Format
类有一个带有Object
参数的方法,Format
的子类预计会将参数限制为它们可以处理的对象类型,它们必须在运行时执行。)
【讨论】:
以上是关于使用 DecimalFormat 进行格式化会引发异常 - “无法将给定对象格式化为数字”的主要内容,如果未能解决你的问题,请参考以下文章
java 使用DecimalFormat进行数字的格式化实例详解
Java数据格式化使用DecimalFormat 对Float和double进行格式化