使用DecimalFormat进行格式化会抛出异常 - "无法将给定的对象格式化为数字"

时间:2017-07-24 06:44:42

标签: java exception overloading illegalargumentexception decimalformat

这可能看起来像是一个重复的问题,但我尝试了以下所有链接,但无法得到正确答案。

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方法采用对象类型参数,这就是为什么我传递给出异常的String对象

  

线程中的异常" main" java.lang.IllegalArgumentException:不能   将对象格式化为数字。

但是当我将double值作为参数时,程序运行正常。但是,如果使用Object类型参数定义方法,为什么我在传递String时遇到异常而在传递double时没有获得异常?

3 个答案:

答案 0 :(得分:11)

format()的{​​{1}}方法已超载。

在工作案例中,您正在调用:

DecimalFormat

在失败的情况下,你正在调用:

 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,{{1 },... 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 {{1} }}。
我建议采用第一种方式(传递Number),因为在您的代码中使用Double原语更为自然。
第二个需要从Double.valueOf(yourString)double进行额外的转换操作。

答案 1 :(得分: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());

答案 2 :(得分:1)

答案在javadoc。它清楚地说,&#34;数字可以是Number&#34;的任何子类,并且它表示它抛出IllegalArgumentException&#34;如果number为null或者不是Number的实例。&#34 ;

(那么为什么他们只是让参数成为Number类型?因为该类是抽象Format类的子类,不限于数字格式。显然,期望是,虽然一般Format类有一个带有Object参数的方法,但Format的子类应该将参数限制为它们可以处理的对象类型,他们必须在运行时做。)