【问题标题】:Different output of sorting code in Java 6 and Java 8Java 6 和 Java 8 中排序代码的不同输出
【发布时间】:2021-09-28 18:00:29
【问题描述】:

我编写了以下代码来对我的数据进行排序。 此代码的输出在 Java 6 和 Java 8 中是不同的。而且比较对象的顺序是相反的,我认为这会导致最终输出发生变化。 排序算法可能不正确,但有人可以解释一下为什么会这样吗?

请检查 Java 6 和 Java 8 中的附加代码和输出。

代码

package assignements;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

class ComparableObject {
    private String id;
    private String name;
    private boolean hidden;
    private Integer order;


    ComparableObject() {
    }

    ComparableObject(String id, String name, boolean hidden, Integer columnOrder) {
        this.id = id;
        this.name = name;
        this.hidden = hidden;
        this.order = columnOrder;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public boolean isHidden() {
        return hidden;
    }

    public void setHidden(boolean hidden) {
        this.hidden = hidden;
    }

    public Integer getOrder() {
        return order;
    }

    public void setOrder(Integer order) {
        this.order = order;
    }
}

public class ComparatorPoc {

    public static void main(String[] args) {
        List<ComparableObject> list = new ArrayList<ComparableObject>();
        list.add(new ComparableObject("1547", "id", false, 10));
        list.add(new ComparableObject("1548", "name", true, 20));
        list.add(new ComparableObject("1592", "customername", false, 30));
        list.add(new ComparableObject("1549", "customername", true, 40));
        list.add(new ComparableObject("1551", "OrderTo", false, 50));
        list.add(new ComparableObject("1553", "PO", true, 60));

        Collections.sort(list, new Comparator<ComparableObject>() {
            @Override
            public int compare(ComparableObject o1, ComparableObject o2) {
                System.out.println(o1.getName());
                System.out.println(o2.getName());
                System.out.println("****************");
                boolean o1Hidden = o1.isHidden();
                boolean o2Hidden = o2.isHidden();
                if (o1Hidden && o2Hidden)
                    return 0;
                else if (o1Hidden)
                    return 1;
                else
                    return -1;
            }
        });

        for (ComparableObject p : list) {
            System.out.println("Id=" + p.getId() + " Name=" + p.getName() + " Column Order=" + p.getOrder() + " IsHidden=" + p.isHidden());
        }
    }
}

Java 6 输出

id
name
****************
name
customername
****************
id
customername
****************
name
customername
****************
customername
OrderTo
****************
name
OrderTo
****************
customername
OrderTo
****************
customername
PO
****************
Id=1547 Name=id Column Order=10 IsHidden=false
Id=1592 Name=customername Column Order=30 IsHidden=false
Id=1551 Name=OrderTo Column Order=50 IsHidden=false
Id=1548 Name=name Column Order=20 IsHidden=true
Id=1549 Name=customername Column Order=40 IsHidden=true
Id=1553 Name=PO Column Order=60 IsHidden=true

Java 8 输出

name
id
****************
customername
name
****************
customername
name
****************
customername
id
****************
customername
id
****************
customername
name
****************
OrderTo
name
****************
OrderTo
id
****************
OrderTo
customername
****************
PO
id
****************
PO
customername
****************
Id=1551 Name=OrderTo Column Order=50 IsHidden=false
Id=1592 Name=customername Column Order=30 IsHidden=false
Id=1547 Name=id Column Order=10 IsHidden=false
Id=1548 Name=name Column Order=20 IsHidden=true
Id=1549 Name=customername Column Order=40 IsHidden=true
Id=1553 Name=PO Column Order=60 IsHidden=true

【问题讨论】:

  • 只要两个对象都没有“隐藏”,您的比较器就会返回-1,因此它没有正确实现比较器协议。因此排序行为不是确定性的。
  • 您可以使用return (o1Hidden ^ o2Hidden) ? o1Hidden ? 1 : -1 : 0; 修复您的比较器。区别在于returns 0o1Hidden == o2Hidden。由于该案例已解决,您可以继续在 o1Hiddenreturning 1 for true and -1 for false 上进行专门测试。现在这是否是您想要的(或满足您的排序要求)取决于您。
  • 感谢@kaya3 和 WJS 的建议。我知道我的排序代码有一个错误,我知道如何解决这个问题。我只是想知道为什么 Java 6 和 8 中的比较顺序会发生变化。

标签: sorting java-8 comparator java-6


【解决方案1】:

使用Comparator 的方法提供的所有保证都假定Comparator 正确实现the compare contract。但是有几种简单的方法可以巧妙地破解它。

在您的具体情况下,当hiddena 和@ 都为false 时,您打破了compare(a, b)compare(b, a) 的符号必须相反的约定(除非它们都返回0) 987654332@:

实施者必须确保所有xysgn(compare(x, y)) == -sgn(compare(y, x))

由于您违反了合同,因此不再指定 sort() 方法的确切行为。

Java 6 和 Java 8 之间使用的排序算法可能发生了变化,这意味着它们处理这种(未指定)情况的方式不同。这不是sort 代码中的错误。

【讨论】:

  • 这是一个很好的例子,说明为什么人们应该仔细阅读并遵守 API 中指定的合同。否则,严重的后果可能会导致实际应用。
  • @WJS: Comparatorequals/hashCode 绝对是 JDK 中最大的绊脚石。
  • ...您可以通过让内置工具完成这项工作来节省很多麻烦,即list.sort(Comparator.comparing(ComparableObject::isHidden)); 不仅仅是节省打字。它消除了错误来源。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-10-27
  • 1970-01-01
  • 1970-01-01
  • 2011-10-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多