我正在从Java 6迁移到Java 8,并注意到Comparator接口的一些特殊之处。对此有任何见解都会很有帮助。
当我切换到Java 8时,对象的顺序在"compare"方法中被切换,列表排序失败。我回到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;
}
}
}
如果你们对这个问题有什么见解的话会很有帮助的
您的Comparator
不是有效的Comparator
。它只查看要比较的第一项;它忽略了第二项。它不能返回一个负数,这意味着第一项永远不能被认为"小于"第二项。
用于排序列表的算法恰好在Java 6中工作(毕竟它有50/50的机会),但在Java 6和Java 8之间,算法一定发生了变化。
您需要根据compare
方法的契约来修复Comparator
的逻辑:
比较它的两个参数的顺序。当第一个参数小于、等于或大于第二个参数时,返回负整数、零或正整数。
另外,它不需要是Comparator<Object>
。如果将其设置为Comparator<Record>
,则compare
方法可以使用Record
s而不是Object
s。
您的比较器完全坏了。如果它到现在还能起作用,那纯粹是运气。
如果您执行compare(a, b)
和compare(b,a)
,则
-
a
和b
相等,两个调用都返回0 -
a
和b
不相等,一个返回正数,另一个返回负数
但是比较器从不返回负值。这就违反了compare
合约。您没有设置订单关系。
作为对现有答案的补充,我将添加以下问题:在Java 8中,您应该删除自定义Comparator实现的全部内容。显然,您希望对记录进行排序,以便所有只读记录排在第一位,然后是所有可写记录。这是Java 8中的一行代码:
list.sort(Comparator.comparing(Record::getIsReadOnly).reverseOrder());