java-比较两个通用数字的值
我想与两个类型均为TreeSet的变量进行比较。现在,我想知道两个变量中的哪个大于另一个或相等。 不幸的是,我还不知道确切的类型,我只知道它将是Number的子类型。我该怎么做?
编辑:我尝试了使用TreeSets的另一种解决方法,该方法实际上可以自然排序(当然可以,除AtomicInteger和AtomicLong外,Number的所有子类都实现了Comparable)。 因此,我将丢失重复的值。 使用Lists时,由于绑定不匹配,因此Collection.sort()将不接受我的列表。 非常不满意。
12个解决方案
31 votes
这应该适用于所有扩展Number并与其可比较的类。 与Sarmun答案相比,通过添加&Comparable,您可以删除所有类型检查,并免费提供运行时类型检查和错误抛出。
class NumberComparator implements Comparator {
public int compare( T a, T b ) throws ClassCastException {
return a.compareTo( b );
}
}
BennyBoy answered 2019-12-31T20:55:18Z
30 votes
一个有效的(但脆弱的)解决方案是这样的:
class NumberComparator implements Comparator {
public int compare(Number a, Number b){
return new BigDecimal(a.toString()).compareTo(new BigDecimal(b.toString()));
}
}
但是,它仍然不是很好,因为它依靠NaN返回可以由false解析的值(标准Java Number类可以执行,但是Number合同不需要)。
七年后编辑:正如评论中所指出的,您可以考虑(至少?)三种特殊情况NaN:
NaN,它大于所有值,除了相等的自身
NaN,它等于所有事物,除了等于它的自身
NaN,这比较麻烦/不可能进行比较,因为与NaN进行的所有比较都会导致false,包括检查自身是否相等。
gustafc answered 2019-12-31T20:54:57Z
14 votes
一种可能适合您的解决方案是不与T extends Number一起使用,而与T extends Number & Comparable一起使用。这种类型的意思是:“ T只能设置为实现两个接口的类型。”
这样您就可以编写适用于所有可比较数字的代码。 静态打字且优雅。
这与BennyBoy提出的解决方案相同,但是它适用于各种方法,不仅适用于比较器类。
public static > void compfunc(T n1, T n2) {
if (n1.compareTo(n2) > 0) System.out.println("n1 is bigger");
}
public void test() {
compfunc(2, 1); // Works with Integer.
compfunc(2.0, 1.0); // And all other types that are subtypes of both Number and Comparable.
compfunc(2, 1.0); // Compilation error! Different types.
compfunc(new AtomicInteger(1), new AtomicInteger(2)); // Compilation error! Not subtype of Comparable
}
Lii answered 2019-12-31T20:55:47Z
12 votes
问了类似的问题并在这里研究了答案之后,我想到了以下内容。 我认为它比gustafc提供的解决方案更有效,更强大:
public int compare(Number x, Number y) {
if(isSpecial(x) || isSpecial(y))
return Double.compare(x.doubleValue(), y.doubleValue());
else
return toBigDecimal(x).compareTo(toBigDecimal(y));
}
private static boolean isSpecial(Number x) {
boolean specialDouble = x instanceof Double
&& (Double.isNaN((Double) x) || Double.isInfinite((Double) x));
boolean specialFloat = x instanceof Float
&& (Float.isNaN((Float) x) || Float.isInfinite((Float) x));
return specialDouble || specialFloat;
}
private static BigDecimal toBigDecimal(Number number) {
if(number instanceof BigDecimal)
return (BigDecimal) number;
if(number instanceof BigInteger)
return new BigDecimal((BigInteger) number);
if(number instanceof Byte || number instanceof Short
|| number instanceof Integer || number instanceof Long)
return new BigDecimal(number.longValue());
if(number instanceof Float || number instanceof Double)
return new BigDecimal(number.doubleValue());
try {
return new BigDecimal(number.toString());
} catch(final NumberFormatException e) {
throw new RuntimeException("The given number (\"" + number + "\" of class " + number.getClass().getName() + ") does not have a parsable string representation", e);
}
}
rolve answered 2019-12-31T20:56:07Z
5 votes
最“通用”的Java原语数字是double,因此只需使用
a.doubleValue() > b.doubleValue()
在大多数情况下应该足够了,但是...将数字转换为双精度时,这里存在一些细微问题。 例如,BigInteger可以实现以下功能:
BigInteger a = new BigInteger("9999999999999992");
BigInteger b = new BigInteger("9999999999999991");
System.out.println(a.doubleValue() > b.doubleValue());
System.out.println(a.doubleValue() == b.doubleValue());
结果是:
false
true
尽管我希望这是非常极端的情况,但这是可能的。 而且-没有通用的100%准确方法。 数字接口没有像extraValue()这样的方法可以转换为某种能够以完美的方式表示数字而不丢失任何信息的类型。
实际上,实际上不可能有这样的完美数字-例如,使用有限空间的任何算术运算都无法表示数字Pi。
kopper answered 2019-12-31T20:56:45Z
2 votes
这应该适用于所有扩展Number并与其可比较的类。
class NumberComparator implements Comparator {
public int compare(T a, T b){
if (a instanceof Comparable)
if (a.getClass().equals(b.getClass()))
return ((Comparable)a).compareTo(b);
throw new UnsupportedOperationException();
}
}
Sarmun answered 2019-12-31T20:57:05Z
2 votes
if(yourNumber instanceof Double) {
boolean greaterThanOtherNumber = yourNumber.doubleValue() > otherNumber.doubleValue();
// [...]
}
注意:不一定需要.compareTo()检查-取决于您要比较它们的精确程度。 您当然可以始终使用.doubleValue(),因为每个数字都应提供此处列出的方法。
编辑:如评论中所述,您将(始终)必须检查BigDecimal和朋友。 但是他们提供了.compareTo()方法:
if(yourNumber instanceof BigDecimal && otherNumber instanceof BigDecimal) {
boolean greaterThanOtherNumber = ((BigDecimal)yourNumber).compareTo((BigDecimal)otherNumber) > 0;
}
Tedil answered 2019-12-31T20:57:30Z
1 votes
您可以简单地使用Number's doubleValue()方法进行比较; 但是,您可能会发现结果不够准确,无法满足您的需求。
Steven Mackenzie answered 2019-12-31T20:57:50Z
1 votes
这个如何? 绝对不好,但是它处理了所有必要的情况。
public class SimpleNumberComparator implements Comparator
{
@Override
public int compare(Number o1, Number o2)
{
if(o1 instanceof Short && o2 instanceof Short)
{
return ((Short) o1).compareTo((Short) o2);
}
else if(o1 instanceof Long && o2 instanceof Long)
{
return ((Long) o1).compareTo((Long) o2);
}
else if(o1 instanceof Integer && o2 instanceof Integer)
{
return ((Integer) o1).compareTo((Integer) o2);
}
else if(o1 instanceof Float && o2 instanceof Float)
{
return ((Float) o1).compareTo((Float) o2);
}
else if(o1 instanceof Double && o2 instanceof Double)
{
return ((Double) o1).compareTo((Double) o2);
}
else if(o1 instanceof Byte && o2 instanceof Byte)
{
return ((Byte) o1).compareTo((Byte) o2);
}
else if(o1 instanceof BigInteger && o2 instanceof BigInteger)
{
return ((BigInteger) o1).compareTo((BigInteger) o2);
}
else if(o1 instanceof BigDecimal && o2 instanceof BigDecimal)
{
return ((BigDecimal) o1).compareTo((BigDecimal) o2);
}
else
{
throw new RuntimeException("Ooopps!");
}
}
}
b_erb answered 2019-12-31T20:58:10Z
0 votes
假设您有一些类似的方法:
public T max (T a, T b) {
...
//return maximum of a and b
}
如果您知道只有整数,可以将long和double作为参数传递,则可以将方法签名更改为:
public T max(double a, double b) {
return (T)Math.max (a, b);
}
这将适用于字节,短,整数,长和双精度。
如果您假定可以传递BigInteger或BigDecimal或浮点数和双精度数的组合,则无法创建一种通用方法来比较所有这些类型的参数。
Roman answered 2019-12-31T20:58:43Z
0 votes
如果您的Number实例绝不是Atomic(即AtomicInteger),则可以执行以下操作:
private Integer compare(Number n1, Number n2) throws SecurityException, NoSuchMethodException, IllegalArgumentException, IllegalAccessException, InvocationTargetException {
Class extends Number> n1Class = n1.getClass();
if (n1Class.isInstance(n2)) {
Method compareTo = n1Class.getMethod("compareTo", n1Class);
return (Integer) compareTo.invoke(n1, n2);
}
return -23;
}
这是因为所有非原子Number都实现了可比
编辑:
由于反思,这很昂贵:我知道
编辑2:
当然,这种情况不会出现您想将小数与整数或类似数字进行比较的情况。
编辑3:
假设没有Number的自定义后代没有实现Comparable(感谢@DJClayworth)
Yaneeve answered 2019-12-31T20:59:34Z
0 votes
System.out.println(new BigDecimal(0.1d).toPlainString());
System.out.println(BigDecimal.valueOf(0.1d).toPlainString());
System.out.println(BigDecimal.valueOf(0.1f).toPlainString());
System.out.println(Float.valueOf(0.1f).toString());
System.out.println(Float.valueOf(0.1f).doubleValue());
t _ liang answered 2019-12-31T20:59:49Z