Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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 format method takes Object type argument, so that's why I passed a String object which gives exception

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

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

like image 646
Arun Sudhakaran Avatar asked Jul 24 '17 06:07

Arun Sudhakaran


People also ask

What is number format and DecimalFormat class?

DecimalFormat class is subclass of NumberFormat class and it is used to format numbers by using specify formatting pattern. We can format a number upto 2 decimal place,upto 3 decimal place, using comma to separate digits.

What is DecimalFormat in Java?

DecimalFormat is a concrete subclass of NumberFormat that formats decimal numbers. It has a variety of features designed to make it possible to parse and format numbers in any locale, including support for Western, Arabic, and Indic digits.


3 Answers

The format() method of DecimalFormat is overloaded.

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.

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

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

Under the hood, this method relies on the format(Object number, StringBuffer toAppendTo, FieldPosition pos) method that expects to a number argument that is an instance of the Number class (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 String instance.

To solve the problem, either pass a double primitive as in the success case or convert your String into an instance of Number such as Double with Double.valueOf(yourString).
I advise the first way (passing a double) as it is more natural in your code that already uses double primitives.
The second one requires a additional conversion operation from String to Double.

like image 126
davidxxx Avatar answered Oct 11 '22 18:10

davidxxx


If there is any mathematical calculation then using java.math.BigDecimal class's methods are the better choice for accuracy in result and efficient in performance even numbers are too large. Using java.math.BigDecimal code :

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());
like image 44
Jimmy Avatar answered Oct 11 '22 20:10

Jimmy


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."

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

like image 1
ajb Avatar answered Oct 11 '22 19:10

ajb