9

以前有人问过,但我还没有找到一个体面的实现和解释。

public int compareTo(Object o)
{
    if (this == null || o == null)
    { 
        return 0;
    }
    Tok tmp = (Tok) o;      
    if (this.rang < tmp.rang)
    {
        return -1;
    } else if (this.rang > tmp.rang ) {
        return 1;
    } else {
        return 0;
    }
}

我读了两个我发现的类似问题;他们坚持实施另一种方法。我不明白为什么这不起作用。该方法获取一个额外的对象,并检查它是否是一个有效的实例,或者null,如果null只是返回0;什么是实现 null-safe 的最简单方法compareTo

对我有用的实现是:

public int compareTo(Object o)
{
    if (o == null)
    { 
        return 0;
    }
    Tok tmp = (Tok) o;      
    if (this.rang < tmp.rang)
    {
        return -1;
    } else if (this.rang > tmp.rang ) {
        return 1;
    } else {
        return 0;
    }
}

这不是最佳实施,人们应该关注这里发布的好人作为答案。对于我的特殊情况,这已经足够了,因为它永远不会为空,但接收到的对象可以是空的,并且初始实现状态是否为空返回 0。因此,如果给定对象为空,则返回 0。

4

7 回答 7

12

就个人而言,我喜欢Guava 的Orderingnull 安全比较。您可以指定#nullsFirst()#nullsLast()避免NullPointerExceptions。

其他重要说明,主要来自评论:

  • this从不 null在 Java中
  • 如果您要实现细粒度,请考虑使用GuavaComparisonChaincompareTo()
  • 实现时Comparable,请务必指定类型参数,以便获得编译时类型安全并且不必使用instanceof或强制转换:

    class Tok implements Comparable<Tok> {
        // snip
    
        public int compareTo(Tok other) {
            // snip
        }
    }
    
于 2012-11-22T17:13:11.950 回答
5

返回 0 将意味着thisand是相等的,如果为 nullo则不正确。o此外,this永远不会为空。

当然,它取决于应用程序。您可能想要一个应该等于 null 的对象。你在那里返回什么取决于你,但如果你正在寻找一种通用的 null 安全方法,它并不是很理想。

为了完全通用,我会检查是否onull,如果是,则抛出某种异常。

于 2012-11-22T17:12:08.597 回答
4

我对其他答案不满意:
您不应该在 compareTo 中检查 null。
要求它抛出一个 NullPointerException,否则你会弄乱你的树并且很难找到你的 TreeMap 不工作的原因。

一个非常值得推荐的方法:

 public int compareTo(Tok other) { 
    int thisRang = this.rang; 
    int otherRang = other.rang; 
    return (thisRang < otherRang ? -1 : (thisRang == otherRang ? 0 : 1)); 
  } 
  public int compareTo(Object other) { 
    return compareTo((Tok)other); 
  } 

进一步使其完美,类 Tok 应该是最终的!(否则,当您从 Tok 子类化时可能会遇到问题。(Sun 在上课日期犯了那个错误)

final class Tok {
    int rang;
}

处理 compare 和 equals 并不总是那么容易,考虑使用 HashMap 代替 Trees (TreeMap),那么你不必实现 compareTo。您应该实现 hashCode,您只需在其中返回 this.rang。

最后,强烈推荐它,但不是强制实现 equals()

public boolean equals(Object obj) {
return obj instanceof Tok
    && this.rang() == ((Tok) obj).rang;
}
于 2012-11-22T17:45:21.050 回答
1

比较两个对象可以像任何其他方法一样是空安全的,这里的问题是普通方法有两个参数,但compareTo接收一个参数,另一个是对象本身。

this永远不能为空,这意味着您正在null对象中执行代码(无实例)。在这种情况下, aNullPointerException将在调用 时被抛出compareTo,使其代码无法执行。

方法与对象一样多,因为比较可以基于可以为空的类的字段(旨在排除原始类型的上限)。因此,长话短说,您的空检查应该涵盖您作为参数接收的对象compareTo和使用的字段。此外,如果您有一个包含某些逻辑的外部实例(即实用程序类),您应该检查该实例是否也为空。

作为旁注,如果任何涉及的对象返回,则无论您返回什么,都null必须是一致的并记录在案(您可以返回 -1 或 1,以在开头或结尾放置空值)。只是避免返回 0 (这与equals返回对象true的情况相同null

于 2012-11-22T17:18:24.537 回答
1

看起来很奇怪,但它并不安全。尝试将您的 Tok 添加到 TreeSet 或 TreeMap(作为键),您将获得 NullPointerException。问题是 TreeSet 的实现是基于 TreeMap 的。当您尝试添加(null)时,底层地图将尝试放置您的 null ,这将导致 NPE

于 2012-11-22T17:36:49.763 回答
1

作者坚持他不想从他的 Tok[] 中删除空值。
这是一个允许使用 NULL 值进行排序的灵魂,并且不违反 java 合同

为避免这种情况,您在 Tok 类中创建了一个违反 compareTo 协定的 compareTo,您创建了一个显式 NullSafeComparator:

 /**
 * This comparator accepts null objects,
 * sorts ascending, null values are after non null values.
 */
public static final class NullSafeComparator implements Comparator<Tok> {
    public int compare(Tok o1, Tok o2) {
        int r1 = Integer.MAX_VALUE;
        int r2 = Integer.MAX_VALUE;
        if (o1 != null) {
            r1 = o1.rang;
        }
        if (o2 != null) {
            r2 = o2.rang;
        }
        return (r1 < r2 ? -1 : (r1 == r2 ? 0 : 1));
    }
}

简化类 Tok(删除静态关键字它用于在一个单元测试类中定义所有内容):

public static class Tok {
    int rang;
    public Tok(int rang) {
        this.rang = rang;
    }
    public String toString() {
        return Integer.toString(rang);
    }
}

最后一个单元测试显示:

public void testSort() {

    Tok[] toks = new Tok[5];
    toks[0] = new Tok(3);
    toks[1] = new Tok(1);
    toks[2] = null;
    toks[3] = null;
    toks[4] = new Tok(2);



    Arrays.sort(toks, new NullSafeComparator());



    for (Tok tok: toks) {
        System.out.println(tok);
    }
    assertEquals(1, toks[0]);
    assertNull(toks[4]);
}

这将给出以下期望的结果:

1
2
3
null
null
于 2012-11-23T14:03:54.013 回答
0

根据文档

Note that null is not an instance of any class, and e.compareTo(null) should
throw a NullPointerException even though e.equals(null) returns false.

因此,如果您实现了一个空安全方法,它的行为将是出乎意料的(也就是与文档不一致,并且可能与 API 的其余部分不一致)。

于 2014-05-02T18:11:05.403 回答