Java 使用 DecimalFormat 进行格式化会引发异常 - “无法将给定的对象格式化为数字”

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/45274167/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 01:56:51  来源:igfitidea点击:

Formatting using DecimalFormat throws exception - "Cannot format given Object as a Number"

javaexceptionoverloadingillegalargumentexceptiondecimalformat

提问by Arun Sudhakaran

This might look like a repeated question but I tried in all the below links and can't get a proper answer.

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

Cannot format given Object as a Number ComboBox

无法将给定的对象格式化为数字组合框

Illegal Argument Exception

非法参数异常

But I'm not getting what's wrong. Here is my code

但我不明白出了什么问题。这是我的代码

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

The formatmethod takes Object type argument, so that's why I passed a String object which gives exception

format方法采用 Object 类型参数,这就是为什么我传递了一个给出异常的 String 对象

Exception in thread "main" java.lang.IllegalArgumentException: Cannotformat given Object as a Number.

线程“main”中的异常 java.lang.IllegalArgumentException:无法将给定的对象格式化为数字。

But when I give double value as argument the program works fine. But if the method is defined with Objecttype argument why I'm getting an exception while passing a Stringand not getting exception while passing double?

但是当我给出 double 值作为参数时,程序运行良好。但是,如果该方法是使用Object类型参数定义的,为什么我在传递 a 时String收到异常,而在传递时却没有收到异常double

采纳答案by davidxxx

The format()method of DecimalFormatis overloaded.

format()方法DecimalFormat被重载。

In the working case, you are invoking :

在工作情况下,您正在调用:

 public final String format(double number)

And in the failing case, you are invoking :

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

 public final String format (Object obj) 

The first method takes a very specific argument. It expects a double.

第一种方法需要一个非常具体的参数。它期望一个double.

This is not the case of the second one, which the type accepted is very broad : Objectand where so the check on the type passed is performed at runtime.

这不是第二个的情况,它接受的类型非常广泛:Object因此在运行时对传递的类型进行检查。

By providing a argument that is not a doublebut a String, the method invoked is the second one.

通过提供一个不是 adouble而是 a的参数,String调用的方法是第二个。

Under the hood, this method relies on the format(Object number, StringBuffer toAppendTo, FieldPosition pos)method that expects to a numberargument that is an instance of the Numberclass (Short, Long, ... Double):

在幕后,此方法依赖于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");
    }
}

But it is not the case as you passed to it a Stringinstance.

但事实并非如此,因为您向它传递了一个String实例。

To solve the problem, either pass a doubleprimitive as in the success case or convert your Stringinto an instance of Numbersuch as Doublewith Double.valueOf(yourString).
I advise the first way (passing a double) as it is more natural in your code that already uses doubleprimitives.
The second one requires a additional conversion operation from Stringto Double.

要解决此问题,请double在成功案例中传递一个原语,或者将您String转换为Number诸如Doublewith的实例Double.valueOf(yourString)
我建议第一种方式(传递 a double),因为它在已经使用double原语的代码中更自然。
第二个需要从String到的额外转换操作Double

回答by ajb

The answer is in the javadoc. It says clearly, "The number can be of any subclass of Number", and it says that it throws IllegalArgumentException"if number is null or not an instance of Number."

答案在javadoc 中。它清楚地说,“数字可以是数字的任何子类”,并且它说它抛出IllegalArgumentException“如果数字为空或不是数字的实例”。

(So why don't they just make the parameter a Numbertype? Because the class is a subclass of the abstract Formatclass that isn't restricted to numeric formatting. The expectation, apparently, is that while the general Formatclass has a method with an Objectparameters, subclasses of Formatare expected to limit the parameters to the object types that they can handle, which they have to do at run time.)

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