比较者一般合同违规

时间:2016-12-07 12:35:58

标签: java sorting collections

我已经读过关于传递比较器的所有线程,我不明白为什么这个比较器函数违反了规则。如果有人可以清洁我的眼睛,我认为这很简单,但我无法得到它

Stack is:

java.util.TimSort.mergeLo(TimSort.java:747)
java.util.TimSort.mergeAt(TimSort.java:483)
java.util.TimSort.mergeCollapse(TimSort.java:410)

我的对象(简化)

public class SleepDetails  {
    private DateTime time;
    private SleepEnum type;
    [...]
}

public enum SleepEnum {
    DEEP(0), LIGHT(1), AWAKE(2), BEGIN(16), END(17);
    [...]
}

比较器静态成为一个类

Comparator<SleepDetails> comparator = new Comparator<SleepDetails>(){
        public int compare(SleepDetails arg0, SleepDetails arg1) {
            int res = arg0.getTime().compareTo(arg1.getTime());
            if (res != 0)
                return res;
            if (arg0.getType() == arg1.getType())
                return 0;
            switch(arg0.getType()) {
              case BEGIN:
                return -1;
              case END:
                return 1;
              default:
                return 0;
            }
        }
    };

主要是我希望按日期对事件进行排序,如果两个事件具有相同的日期时间,则将开始事件放在第一位,将结束事件放在最后。

我没有触发错误的集合

2 个答案:

答案 0 :(得分:5)

如果您比较具有相同SleepDetails的两个getTime()个实例,其中一个实例有getType() BEGIN,另一个则为AWAKE。

compare (one, two)

会给-1

compare (two, one)

会给0

这违反了合同:

  

实现者必须确保所有x和y的sgn(compare(x,y))== -sgn(compare(y,x))。

您还必须使用arg1.getType()方法检查compare(只要arg0.getType()既不是BEGIN也不是END)。

    public int compare(SleepDetails arg0, SleepDetails arg1) {
        int res = arg0.getTime().compareTo(arg1.getTime());
        if (res != 0)
            return res;
        if (arg0.getType() == arg1.getType())
            return 0;
        switch(arg0.getType()) {
          case BEGIN:
            return -1;
          case END:
            return 1;
          default:
            switch(arg1.getType()) {
              case BEGIN:
                return 1;
              case END:
                return -1;
              default:
                return 0;
            }
        }
    }

答案 1 :(得分:1)

问题是您的代码不区分BEGIN和END以外的类型的枚举值。特别是,当第一个类型既不是BEGIN也不是END时,它返回零,而不管第二个类型。

然而,这种行为并不对称:如果你交换BEGIN和LIGHT对中的两个项目,你会得到-1和0,打破对称性。

您可以将除BEGIN和END之外的所有类型视为彼此相等,但在决定相等时您需要使用双方。