【问题标题】:Formatting using DecimalFormat throws exception - "Cannot format given Object as a Number"使用 DecimalFormat 进行格式化会引发异常 - “无法将给定对象格式化为数字”
【发布时间】: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 时没有遇到异常?

【问题讨论】:

    标签: java exception overloading illegalargumentexception decimalformat


    【解决方案1】:

    DecimalFormatformat() 方法被重载。

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

     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 类的实例(ShortLong、...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 的实例,例如DoubleDouble.valueOf(yourString)
    我建议第一种方式(传递double),因为它在您的代码中已经使用double 原语更自然。
    第二个需要额外的从StringDouble 的转换操作。

    【讨论】:

    • 你好 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 的子类预计会将参数限制为它们可以处理的对象类型,它们必须在运行时执行。)

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-03-03
        相关资源
        最近更新 更多