为什么我的比较方法违反了其总合同?

时间:2014-01-07 11:17:24

标签: java comparator

public static Comparator<Container> DEPARTURE = new Comparator<Container>() {
    @Override
    public int compare(Container container1, Container container2) {
        if (container1.departure.time.isBefore(container2.departure.time))
            return -1;
        else if (container1.departure.time.equals(container2.departure.time) && 
                 container1.departure.maxDuration == container2.departure.maxDuration && 
                 container1.departure.transportCompany.equals(container2.departure.transportCompany) && 
                 container1.departure.transportType == container2.departure.transportType)
            return 0;
        else
            return +1;
    }
};

离开变量只是包含以下字段的对象的实例:

    public DateTime time;
    public int maxDuration;
    public TransportType transportType;
    public String transportCompany;

P.S。 time对象是来自Joda-Time库的DateTime实例,TransportType是包含常量Train,Seaship,Barge和Truck的枚举。

修改

好的,我将比较器编辑成以下内容:

    public static Comparator<Container> DEPARTURE = new Comparator<Container>() {
        @Override
        public int compare(Container container1, Container container2) {
            if (container1.departure.time.isBefore(container2.departure.time))
                return -1;
            else if (container1.departure.time.isBefore(container2.departure.time))
                return +1;
            else {
                if (container1.departure.maxDuration == container2.departure.maxDuration && container1.departure.transportType == container2.departure.transportType && container1.departure.transportCompany.equals(container2.departure.transportCompany))
                    return 0;
                else
                    return +1;
            }
        }
    };

但这显然违反了一般合同。我如何按时间排序,然后按照其他属性对具有相同时间的对象进行排序,只关注它们是否相等?希望这是有道理的......

编辑:解决方案

谢谢大家回答我的问题!在研究了你的评论之后,我提出了以下似乎有效的解决方案(虽然没有经过全面测试):

我实际上将比较部分移到他的班级,因为我还需要通过抵达进行比较。我决定简单地按所有属性排序(连续时间,maxDuration,transportCompany和transportType),我想出的解决方案是:

    public static Comparator<Container> ARRIVAL = new Comparator<Container>() {
        @Override
        public int compare(Container container1, Container container2) {
            return container1.arrival.compareTo(container2.arrival);
        }
    };

    public static Comparator<Container> DEPARTURE = new Comparator<Container>() {
        @Override
        public int compare(Container container1, Container container2) {
            return container1.departure.compareTo(container2.departure);
        }
    };

然后是compareTo方法:

    @Override
    public int compareTo(LocationMovement lm) {
        if (this.time.isBefore(lm.time))
            return -1;
        else if (this.time.isAfter(lm.time))
            return +1;
        else {
            int c = this.maxDuration - lm.maxDuration;
            if (c != 0) return c;

            c = this.transportCompany.compareTo(lm.transportCompany);
            if (c != 0) return c;

            c = this.transportType.ordinal() - lm.transportType.ordinal();
            return c;
        }
    }

3 个答案:

答案 0 :(得分:4)

总合同是

COMPARATOR.compare(a, b) = - COMPARATOR.compare(b, a)

在你的情况下,单向返回-1的代码可以返回0另一个。

答案 1 :(得分:1)

为了实现compare,您检查的所有内容必须具有彼此“较小”,“更大”或“相等”的概念,然后您必须确定其中的顺序检查它们,返回较小/更大的第一个不相等的项目。这样,您就满足compare(a, b)必须与compare(b, a)相反的合同。如果您所比较的所有部分都没有“更大”或“更小”的概念(例如,传输类型),那么要么您无法实现compare,要么必须强制执行任意(但可靠)对它们的更大/更小的解释。

这是一个概念示例。在这种情况下,我(任意)选择的顺序是:时间,持续时间,公司和类型。但是不同的顺序可能更合理。这只是一个例子。另外,你还没有说transportType的类型是什么,所以我假设它有一个compareTo方法;显然它可能没有,你可能需要调整它。

public static Comparator<Container> DEPARTURE = new Comparator<Container>() {
    @Override
    public int compare(Container container1, Container container2) {
        int rv;

        // Times
        rv = container1.departure.time.compareTo(container2.departure.time);
        if (rv == 0) {
            // Duration
            if (container1.departure.maxDuration < container2.departure.maxDuration) {
                rv = -1;
            }
            else if (container1.departure.maxDuration > container2.departure.maxDuration) {
                rv = 1;
            }
            else {
                // Transport company
                rv = container1.departure.transportCompany.compareTo(container2.departure.transportCompany);
                if (rv == 0) {
                    // Transport type
                    rv = container1.departure.transportType.compareTo(container2.departure.transportType);
                }
            }
        }
        return rv;
    }
};

答案 2 :(得分:0)

请注意,如果两个容器c1c2具有相同的departure.time,但其他属性不同,那么compare(c1, c2)compare(c2, c1)将返回{ {1}},即+1c1>c2

相反,您应该完全删除其他字段,或者在嵌套或顺序c2>c1中单独比较它们,以防出发时间相等。

请看一下这个answer to a related question,以便用多种属性比较对象。