简体   繁体   English

你如何干净地实现compareTo方法?

[英]How do you implement compareTo methods cleanly?

Currently I am writing a compareTo method for quadratic functions in the form: ax^2 + bx + c. 目前我正在编写一个用于二次函数的compareTo方法,形式为:ax ^ 2 + bx + c。

a, b, c are integer coefficients that are passed to the class through the constructor. a,b,c是通过构造函数传递给类的整数系数。

In the compareTo method, I am supposed to first compare the a-coefficients between two functions, but if they are equal, I compare the b-coefficients. 在compareTo方法中,我应该首先比较两个函数之间的a系数,但如果它们相等,我比较b系数。 If the b's are equal, I compare the c's. 如果b是相等的,我比较c。

The method that I came up for this ended up being pretty ugly: 我为此提出的方法最终变得非常难看:

public int compareTo(QuadraticFunction other)
{
    if (a > other.a)
        return 1;
    else if (a < other.a)
        return -1;
    else if (b > other.b)
        return 1;
    else if (b < other.b)
        return -1;
    else if (c > other.c)
        return 1;
    else if (c < other.c)
        return -1;
    else
        return 0;
}

So I was wondering, if you have these "tiered" systems of comparisons (like compare a's before b's before c's), what's the best way to implement them? 所以我想知道,如果你有这些“分层”的比较系统(比如在c之前比较a之前的b),那么实现它们的最佳方法是什么? I can't imagine writing a method like mine if you have to go through 10+ variables. 如果你不得不经历10多个变量,我无法想象会像我一样编写一个方法。

For an arbitrary number of coefficients (all of the same type), you should store them in a List (or something similar), rather than individually-named member variables. 对于任意数量的系数(所有相同类型),您应该将它们存储在List (或类似的东西)中,而不是单独命名的成员变量。 That allows you to convert your example code into an iteration. 这允许您将示例代码转换为迭代。

The Guava Libraries provide an extremely nice tool to do this called ComparisonChain . Guava Libraries提供了一个非常好的工具,称为ComparisonChain

Your code would look something like this: 您的代码看起来像这样:

import com.google.common.base.ComparisonChain;
...
public int compareTo(QuadraticFunction other) {
  return ComparisonChain.start()
    .compare(a, other.a)
    .compare(b, other.b)
    .compare(c, other.c)
    .result();
}

For readability, and to use the built-in compare methods for a, b, c, I would refactor to this: 为了便于阅读,并使用a,b,c的内置比较方法,我将重构为:

public int compareTo(QuadraticFunction other) {
    if (a.equals(other.a)) {
        if (b.equals(other.b))
            return c.compareTo(other.c);
        return b.comapreTo(other.b);
    }
    return a.compareTo(other.a);
}

This code assumes the fields are Number . 此代码假定字段为Number If they are a primitive, either convert them to wrapped type or change a.equals(b) to a == b and change a.compareTo(b) to a - b`. 如果他们是原始的,或者将它们转换为包裹型或改变a.equals(b) to一个== b and change a.compareTo(b)中to一个- B`。

Also note that when an if returns, there is never a need for an else - it's redundant, so remove it. 还要注意,当if返回时,永远不需要else - 它是多余的,所以删除它。

You can use an idiom like the below which breaks the comparison into clear sections by field, only requires one test per field, and uses the signum method to produce the return values. 您可以使用如下所示的成语,将比较分为按字段清除的部分,每个字段只需要一次测试,并使用signum方法生成返回值。

Note, the subtraction below works for int , short , char , or byte fields. 注意,下面的减法适用于intshortcharbyte字段。 For long , float , and double fields you have to use separate checks for < and == to avoid overflow/underflow, and loss of precision due to rounding. 对于longfloatdouble字段,您必须对<==使用单独的检查以避免上溢/下溢,并且由于舍入而导致精度损失。 Be careful of NaN too when comparing floating point values. 比较浮点值时要小心NaN For Comparable fields, you can just set delta to the result of compareTo after using separate conditions to handle null . 对于Comparable字段,您可以在使用单独的条件处理null之后将delta设置为compareTo的结果。

long delta = ((long) a.field1) - b.field1;
if (delta != 0) { return Long.signum(delta); }

delta = ((long) a.field2) - b.field2;
if (delta != 0) { return Long.signum(delta); }

...

return 0;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM