如何清晰地实现compareTo方法?

8

目前我正在编写一个针对二次函数的compareTo方法,其形式为:ax^2 + bx + c。

a、b、c是通过构造函数传递给类的整数系数。

在compareTo方法中,我应该首先比较两个函数之间的a系数,但如果它们相等,我会比较b系数。如果b相等,我会比较c。

我为此想出的方法变得非常丑陋:

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;
}

我在想,如果你有这些“分层”比较系统(例如在比较a之前先比较b,在比较b之前先比较c),那么最好的实现方式是什么?如果有10多个变量需要进行比较,我无法想象编写类似于我的方法。

4个回答

6

对于任意数量的系数(类型相同),您应将它们存储在List(或类似结构)中,而不是单独命名的成员变量。这样可以将示例代码转换为迭代。


@LouisWasserman:没错。但我认为可以相当安全地假设,人们会使用同类类型来表示多项式系数。 - Oliver Charlesworth
同意,但应该提及这个警告以备将来参考。 - Louis Wasserman

2
Guava Libraries提供了一个非常好用的工具来实现这个功能,叫做ComparisonChain。在你的代码中可以这样使用:
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();
}

Java8的新Comparator API是否值得单独回答,还是应该合并到那里? - M. Prokhorov

1
为了提高可读性,并使用内置的比较方法来比较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);
}

这段代码假设字段是Number类型。如果它们是原始类型,要么将它们转换为包装类型,要么将a.equals(b)更改为a == b,并将a.compareTo(b)更改为a - b

另外请注意,当if返回时,永远不需要else - 它是多余的,因此请删除它。


有人可能会认为保留 else 有助于重构。在 OP 的情况下,他/她可能会稍后决定更改代码为 if (cond1) { retval = 1; } else if (cond2) { retval = -1; } else ... return retval; - Oliver Charlesworth

0
你可以使用像下面这样的习语,将比较分成清晰的字段部分,每个字段只需要一个测试,并使用signum方法生成返回值。
请注意,下面的减法适用于intshortcharbyte字段。 对于longfloatdouble字段,您必须使用单独的<==检查来避免溢出/下溢和由于舍入而导致的精度损失。在比较浮点数值时,还要小心NaN。 对于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;

只有当 a.field1 等等都是最多整数时,它才能正常工作。 - Voo
@Voo,没错。原帖中说“a、b、c是整数系数”。 - Mike Samuel
啊,在阅读问题时,我将“整数系数”解释为数学上的意义,但是是的,他很可能真正意思是整数int。不过,我认为在使用这个习惯语时,总是需要一个明确的警告:它已经被误用了几十年,所以我有点戒备心理。 - Voo
@Voo,好的,加了一个警告。 - Mike Samuel

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接