2011-06-06 178 views
15

据说当输入参数为空时,compareTo()应该抛出一个NullPointerException异常。但是,我正在实现一个需要将字段与String类型进行比较的类。这些字段不一定是强制性的。我想知道在这种情况下,当参数字符串为空时,int compareTo()会返回什么?

1)当输入为空时应该返回什么?任何非空字符串是否按字典顺序大于或小于空?

2)如果这被认为是不好的做法,有没有什么论据?我应该强制用户使用空字符串吗?如果使用空字符串,这不会混淆字段不适用的情况和字段为空的情况吗?如果必须抛出异常,那么除了在手册中警告用户之外,还能做什么?

编辑:我可能不会在这里明确表达自己,但在我正在实施的程序中,可能为空的字符串是所有字段或类,它们不应该为空。换句话说,compareTo()使用的对象不能为空,只能是它们的私有字段。所以在这种情况下,我相信如果我正确实现了compareTo(),它不会违反传递要求,因为具有空字段的类将始终被视为相同。我是对的还是我解释这个错误?

谢谢大家的答案!

+0

如何最好地实现它:http://stackoverflow.com/questions/481813/how-to-simplify-a-null-safe-compareto-implementation – 2015-06-02 12:33:27

回答

12

是的,允许null作为实例字段没有问题 - 只要确保它的排序顺序已定义。最自然的就是把它放在所有真正的琴弦之前或之后,但你可以在这里做任何事情,只要一直做。 (例如,你可以进行排序null"null"

这里是一个成员的范例:

class Example implements Comparable<Example> { 

    @Nullable 
    private String member; 

    // TODO: getter, setter, constructor, ... 

    public int compareTo(Example that) { 
     if(this.member == null) 
     if(that.member == null) 
      return 0; //equal 
     else 
      return -1; // null is before other strings 
     else // this.member != null 
     if(that.member == null) 
      return 1; // all other strings are after null 
     else 
      return this.member.compareTo(that.member); 
    } 
} 

请注意,Comparable.compareTo()的规范只对o.compareTo(null)约束(它应该像- null.compareTo(o)一样),但不是关于如何处理字段(它根本没有提到字段,所以只要反对称性,反射性和传递性得到保证,类就可以返回任何想要的东西)。

+0

呃,存在的问题是它不同意规范;-) – EJP 2011-06-07 01:48:49

+2

@EJP:'compareTo'的规范没有说明如何(甚至是否)比较对象的实例字段。 – 2011-06-07 10:48:50

+0

compareTo()的规范说'e.compareTo(null)应该抛出一个NullPointerException'。 – EJP 2011-06-09 10:47:05

23

从Javadoc文档Comparable

注意,空不是 实例的任何类,并e.compareTo(空) 应该抛出一个NullPointerException 即使e.equals(空)返回 假。

7

这将是一个不好的做法,因为它违反的compareTo的 传递 反对称自然不会抛出异常。

Comparable.compareTo文档:

实现程序必须确保 SGN(则x.compareTo(Y))== -sgn(y.compareTo(X))对于所有的x和y。 (这意味着则x.compareTo(Y)必须 抛出一个异常,如果y.compareTo(X) 抛出异常。)

实现类还必须确保 的关系是传递的: (则x.compareTo( y)> 0 & & y.compareTo(z)> 0) 意味着x.compareTo(z)> 0。

最后,实现程序必须确保 则x.compareTo(Y)== 0意味着 SGN(则x.compareTo(Z))== SGN(y.compareTo(Z)),对所有的Z。

更重要的是,在您的对象上使用compareTo来比较它们与字符串是一个坏主意,出于同样的原因:sign(obj.compareTo(str)) != -sign(str.compareTo(obj))。实施自定义Comparator并做任何你想要的。

+0

谢谢!但是,在我正在执行的程序中,可能为空的字符串都是零件或类,它们不应为空。所以在这种情况下,我相信如果我正确实现了compareTo(),它不会违反传递要求,因为具有空字段的类将始终被视为相同。我是对的还是我解释这个错误? – 2011-06-07 00:08:50

+0

比较两个实例可能或可能没有设置实例字段是完全正确的。只要确保你实现了传递。 I.E. c1.compareTo(c2)== -c2.compareTo(c1) – ykaganovich 2011-06-07 00:13:36

+1

仅用于术语:条件'c1.compareTo(c2)== -c2.compareTo(c1)'被称为反对称,而不是传递性。传递性主要是您的报价中的第二个条件(也可能是第三个条件)。 – 2011-06-07 00:18:05

3

由于compareTo文档指出它应该抛出一个NullPointerException,你应该遵循这些准则所以您的实现与接口文档保持一致。这也处理了非空字符串是否按字典顺序小于或大于null的问题。

关于如何处理此问题,您有几个选项。如果空和不适用是不同的,那么你应该把字符串字段包装在你自己的字段类中。例如,假设您可以创建一种可能有isApplicable方法的MyField类型,该方法指示该字段是否适用于此案例(或类似情况)。或者你可以重新考虑你的设计,并确保一个空字符串和N/A真的是两个不同的东西。如果是这样,你需要一种方法来区分两者。

3

您需要确定null是否大于或小于非空值。您可以设计compareTo以满足您班级自然排序的需要,因此这不是一种坏习惯。

相关问题