Say I have three numbers:
Comparable n1 = new Integer(432);
Comparable n2 = new Long(40);
Comparable n3 = new Double(500.12);
I would like to compare these numbers through the Comparable
interface. However, this results in a ClassCastException
.
n1.compareTo(n2);
Is there a way (utility function, external library, ...) to compare numbers of different type? In the example above, the number n2
is smaller than n1
, and n1
is smaller than n3
, semantically.
In the code, I have no knowledge about the concrete type of the numbers. Hence, I rely on the Comparable
interface.
The first answer is exactly right on why you get the ClassCastException - the Comparable interface is generic and can only be used on objects of the same concrete type.
There may be other ways to solve your problem:
If you are sure that all your numbers are primitives (int, long, float, double
) or Objects for the classes that represent primitives (Integer, Long, Float, Double
), then you can just use normal comparison operators e.g. for equivalence to n1.compareTo(n2);
int b = n1 > n2 ? 1 : (n1 < n2 ? -1 : 0);
Number
If you are sure that all your variables are of a Class that extends Number
i.e. AtomicInteger, AtomicLong, BigDecimal, BigInteger, Byte, Double, Float, Integer, Long, Short
, you can use the following:
private int compareNumbers(Number n1, Number n2)
{
Double n2c = n2.doubleValue();
Double n1c = n1.doubleValue();
return n1c.compareTo(n2c);
}
public static void main (String[] args)
{
Integer n1 = new Integer(432);
Long n2 = new Long(40);
Double n3 = new Double(500.12);
System.out.println(compareNumbers(n1,n2));
}
EDIT
In response to comment discussion with OP - we noted that using Double
as the base class for the Number
comparison might give spurious equality if comparing two BigDecimal
or BigInteger
numbers that are beyond the range of Double
(therefore .doubleValue()
returns Double.POSITIVE_INFINITY
or Double.NEGATIVE_INFINITY
as appropriate)
If this is a concern, compareNumbers()
could be altered as follows:
private int compareNumbers(Number n1, Number n2)
{
BigDecimal n2c = new BigDecimal(n2.toString());
BigDecimal n1c = new BigDecimal(n1.toString());
return n1c.compareTo(n2c);
}
/EDIT
Comparable
but don't extend Number
If you can't even be sure that your variables extend Number, and you may be processing a variable with a class that represents a number, implements Comparable, but does not extend Number, I believe you can only compare the arguments if they are of the same class. In this case, this should work, but I can't really imagine the use case:
Comparable n1 = new WierdNonNumberExtendingInteger(432);
Comparable n2 = new WierdNonNumberExtendingLong(40);
Comparable n3 = new WierdNonNumberExtendingDouble(500.12);
Integer b = null;
if (n1.getClass().isInstance(n2))
{
b = n1.compareTo(n2);
}
else
{
System.err.println("Can't compare apples and oranges");
System.err.print("You tried to compare " + n1.getClass().getSimpleName());
System.err.print(" with " + n2.getClass().getSimpleName());
}
System.out.println(b);