切换到 Java 8 时的比较器问题
Comparator issue when switching to Java 8
我正在从 Java 6 移动到 Java 8 并注意到 Comparator 界面有些特殊之处。对此的任何见解都会非常有帮助。
当我切换到Java8时,对象的顺序在“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;
}
}
}
你们对此的任何见解都会非常有帮助
你的比较器完全坏了。如果到现在为止一直有效,那纯属运气。
如果您执行 compare(a, b)
和 compare(b,a)
,则
a
和 b
相等并且都调用 return 0
a
和b
不相等,一个叫return是正数,一个叫负数。
但是您的比较器从来没有return是负值。这违反了 compare
合同。您没有设置订单关系。
另一个赠品提示是您仅使用 r1 来计算结果...
您的 Comparator
无效 Comparator
。它只查看要比较的第一项;它忽略了第二项。它无法返回负数,这意味着第一项永远不会被视为 "less than" 第二项。
用于对列表进行排序的算法恰好在 Java 6 时有效(毕竟它有 50/50 的机会),但算法在 Java 6 和 Java 8.
您需要根据 the compare
method's contract:
修正 Comparator
的逻辑
Compares its two arguments for order. Returns a negative integer, zero, or a positive integer as the first argument is less than, equal to, or greater than the second.
此外,它不需要是 Comparator<Object>
。将其设为 Comparator<Record>
,compare
方法可以使用 Record
秒而不是 Object
秒。
作为对现有答案的补充,我将添加以下内容——来到 Java 8,您应该放弃整个自定义 Comparator 实现。显然你想对记录进行排序,以便所有只读记录排在第一位,然后是所有可写记录。这是 Java 8:
中的一行
list.sort(Comparator.comparing(Record::getIsReadOnly).reverseOrder());
我正在从 Java 6 移动到 Java 8 并注意到 Comparator 界面有些特殊之处。对此的任何见解都会非常有帮助。
当我切换到Java8时,对象的顺序在“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;
}
}
}
你们对此的任何见解都会非常有帮助
你的比较器完全坏了。如果到现在为止一直有效,那纯属运气。
如果您执行 compare(a, b)
和 compare(b,a)
,则
a
和b
相等并且都调用 return 0a
和b
不相等,一个叫return是正数,一个叫负数。
但是您的比较器从来没有return是负值。这违反了 compare
合同。您没有设置订单关系。
另一个赠品提示是您仅使用 r1 来计算结果...
您的 Comparator
无效 Comparator
。它只查看要比较的第一项;它忽略了第二项。它无法返回负数,这意味着第一项永远不会被视为 "less than" 第二项。
用于对列表进行排序的算法恰好在 Java 6 时有效(毕竟它有 50/50 的机会),但算法在 Java 6 和 Java 8.
您需要根据 the compare
method's contract:
Comparator
的逻辑
Compares its two arguments for order. Returns a negative integer, zero, or a positive integer as the first argument is less than, equal to, or greater than the second.
此外,它不需要是 Comparator<Object>
。将其设为 Comparator<Record>
,compare
方法可以使用 Record
秒而不是 Object
秒。
作为对现有答案的补充,我将添加以下内容——来到 Java 8,您应该放弃整个自定义 Comparator 实现。显然你想对记录进行排序,以便所有只读记录排在第一位,然后是所有可写记录。这是 Java 8:
中的一行list.sort(Comparator.comparing(Record::getIsReadOnly).reverseOrder());