【问题标题】:Comparator issue when switching to Java 8切换到 Java 8 时的比较器问题
【发布时间】:2015-08-27 23:18:08
【问题描述】:

我正在从 Java 6 迁移到 Java 8,并注意到 Comparator 接口的一些特殊之处。对此的任何见解都会非常有帮助。

当我切换到 Java 8 时,对象的顺序在“比较”方法中被切换,列表排序失败。我回到java 6,它工作得很好。这是一个测试用例,我在 Java 8 中失败,在 Java 6 中通过。

public class ComparitorTest {

@Test
public void comparatorTest(){
    Record record1 = new Record("First", false);
    Record record2 = new Record("Second", true);
    List<Record> list = new ArrayList<Record>();

    list.add(record1);
    list.add(record2);


    final Comparator<Object> recordComparator = new Comparator<Object>()
            {
                public int compare( Object o1, Object o2 )
                {
                    Record r1 = (Record) o1;
                    Record r2 = (Record) o2;

                    Boolean isReadonly_R1 = r1.getIsReadOnly();
                    Boolean isReadOnly_R2 = r2.getIsReadOnly();

                if( isReadonly_R1.equals( Boolean.TRUE ) )
                    {
                        return 0;
                    }
                    else
                    {
                        return 1;
                    }
                }
            };
            Collections.sort(list, recordComparator);

            assertEquals(list.get(0).name, "Second");
            assertEquals(list.get(1).name, "First");

}



class Record {
    boolean isReadOnly; 
    String name;

    public Record(String name, boolean value) {
        isReadOnly =value;
        this.name = name;
    }

     boolean getIsReadOnly() {
        return isReadOnly;
    }
}   

}

你们对此的任何见解都会非常有帮助

【问题讨论】:

    标签: java sorting java-8 comparator java-6


    【解决方案1】:

    您的Comparator 不是有效的Comparator。它只查看要比较的第一项;它忽略了第二项。它不能返回负数,这意味着第一项永远不能被认为“小于”第二项。

    用于对列表进行排序的算法碰巧在 Java 6 中有效(毕竟它有 50/50 的机会),但该算法在 Java 6 和 Java 8 之间肯定发生了变化。

    您需要根据the compare method's contract 修复您的Comparator 的逻辑:

    比较它的两个参数的顺序。返回负整数、零或正整数,因为第一个参数小于、等于或大于第二个参数。

    此外,它不需要是Comparator&lt;Object&gt;。将其设为Comparator&lt;Record&gt;compare 方法可以采用Records 而不是Objects。

    【讨论】:

    • 是的,算法改变了。在 Java 7 中引入了 TimSort。还有一个允许恢复到旧算法的系统属性,但是由于应该首选修复损坏的比较器,所以我不会浪费时间查找该属性的确切名称......
    【解决方案2】:

    你的比较器完全坏了。如果它一直工作到现在,那纯属运气。

    如果您选择compare(a, b)compare(b,a),则选择任一

    • ab 相等,两个调用都返回 0

    • ab 不相等,一个调用返回正数,另一个返回负数。

    但是您的比较器从不返回负值。这违反了compare 合同。您没有设置订单关系。

    另一个赠品提示是您只使用 r1 来计算结果...

    【讨论】:

      【解决方案3】:

      作为对现有答案的补充,我将添加以下内容——在 Java 8 中,您应该放弃整个自定义 Comparator 实现。显然您想对记录进行排序,以便所有只读记录排在第一位,然后是所有可写记录。这是 Java 8 中的单行代码:

      list.sort(Comparator.comparing(Record::getIsReadOnly).reverseOrder());
      

      【讨论】:

        猜你喜欢
        • 2021-11-18
        • 1970-01-01
        • 2017-10-28
        • 2015-11-02
        • 1970-01-01
        • 2017-11-16
        • 2012-09-01
        • 2019-03-13
        • 1970-01-01
        相关资源
        最近更新 更多