Formatting using DecimalFormat throws exception - "Cannot format given Object as a Number"
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
.
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());