当参数字符串为null时,int compareTo()应该返回什么?

时间:2011-06-06 23:56:45

标签: java string null nullpointerexception compareto

据说当输入参数为null时,compareTo()应抛出NullPointerException。但是,我正在实现一个需要将字段与String类型进行比较的类。这些字段不必是强制性的。我想知道在这种情况下,

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

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

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

谢谢大家的答案!

6 个答案:

答案 0 :(得分:25)

来自Comparable

的javadoc
  

请注意,null不是。的实例   任何类,和e.compareTo(null)   应抛出NullPointerException   即使e.equals(null)返回   假的。

答案 1 :(得分:13)

是的,允许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)一样,即抛出NullPointerException),但不是{{1}处理字段(它根本没有提到字段,因此只要确保反对称性,反身性和传递性,类就可以返回它想要的任何东西。)

答案 2 :(得分:7)

不抛出异常是不好的做法,因为它违反了compareTo的传递反对称性质。

来自Comparable.compareTo文档:

  

实施者必须确保   sgn(x.compareTo(y))==   -sgn(y.compareTo(x))表示所有x和y。 (这意味着x.compareTo(y)必须   抛出异常iff y.compareTo(x)   抛出异常。)

     

实施者还必须确保这一点   这种关系是传递性的:   (x.compareTo(y)&gt; 0&amp; y.compareTo(z)&gt; 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并在其中执行任何操作。

答案 3 :(得分:3)

由于compareTo的文档声明它应该抛出NullPointerException,因此您应该遵循这些准则,以便您的实现与界面文档保持一致。这也解决了非空字符串是否在字典上小于或大于null的问题。

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

答案 4 :(得分:3)

您需要确定null是否大于或小于非null值。您可以设计compareTo以满足班级自然顺序的需要,因此这不是一种不好的做法。

答案 5 :(得分:0)

除了接受Paulo Ebermann的答案之外,如果您需要处理 ASC / DESC 订单,则可以这样做。 (我们假设NULL总是按正常的升序排在非NULL之前,否则降序。)

    final boolean sortAsc = false; // Suppose this TRUE/FALSE is for ASC/DESC
    
    objects.sort(new Comparator<Example>() {

        @Override
        public int compare(Example e1, Example e2) {

            if (e1.getMember() == null && e2.getMember() == null) {
                return 0; // Both NULLs are equal
            }
            else if (e1.getMember() == null && e2.getMember() != null) {
                return sortAsc ? -1 : 1; // NULLs should precede non-NULLs in ascending order, follow in descending order
            }
            else if (e1.getMember() != null && e2.getMember() == null) {
                return sortAsc ? 1 : -1; // Non-NULLs should follow NULLs in ascending order, precede in descending order
            } else {
                // Both non-NULLs
                return sortAsc ? e1.getMember().compareTo(e2.getMember()) 
                               : e2.getMember().compareTo(e1.getMember());
            }
        }
        
    });