Gov*_*van 5 java sorting collections comparator java-8
最近我将我们的应用程序jdk从Java 6更新为Java 8,但仍将源语言级别保持为Java 6.更改后,我们的一个单元测试失败了.我注意到LinkedList的Collections.sort在Java 8和Java 6中的工作方式不同.即使我是JDk 1.8的Source Level java 8,我也会得到相同的不同行为.要重新创建问题:定义下面的枚举:
public enum Weight {
A(1), B(0), C(0), D(0), E(2);
public int getWeight() {
return weight;
}
private int weight;
Weight(int weight) {
this.weight = weight;
}
@Override
public String toString() {
return name() + '(' + weight + ')';
}
}
Run Code Online (Sandbox Code Playgroud)
和一个主类如下:
public class Main {
public static void main(String[] args) {
List<Weight> weightList = new LinkedList<Weight>();
weightList.add(Weight.A);
weightList.add(Weight.B);
weightList.add(Weight.C);
weightList.add(Weight.D);
weightList.add(Weight.E);
Collections.sort(weightList, new Comparator<Weight>() {
@Override
public int compare(Weight o1, Weight o2) {
return o1.getWeight() > o2.getWeight()? 1:0;
}
});
System.out.print(weightList);
}
}
Run Code Online (Sandbox Code Playgroud)
在Java 6下运行代码的输出是:"C:\ Program Files\Java\jdk1.6.0_45\bin\java"
[B(0),C(0),D(0),A(1),E(2)]
和在java 8下运行代码的输出是:
"C:\ Program Files(x86)\ Java\jdk1.8.0_161\bin\java"
[A(1),B(0),C(0),D(0),E(2)]
我从变型LinkedList来ArrayList和我得到同样的结果,但如果我改变比较如下那么Java 8将会对数组进行排序:
Collections.sort(weightList, new Comparator<Weight>() {
@Override
public int compare(Weight o1, Weight o2) {
return o1.getWeight() > o2.getWeight()? 1:-1;
}
});
Run Code Online (Sandbox Code Playgroud)
如您所见,java 8似乎没有正确排序代码.Java中是否有错误或者我像往常一样遗漏了什么?
Joh*_*ica 11
public int compare(Weight o1, Weight o2) {
return o1.getWeight() > o2.getWeight()? 1:0;
}
Run Code Online (Sandbox Code Playgroud)
此定义不符合Java API预期的合同.sort如果你传递一个无效的行为是不明确的Comparator.
实施者必须确保
sgn(compare(x, y)) == -sgn(compare(y, x))为所有人x和y.实现者还必须确保关系是可传递的:
((compare(x, y)>0) && (compare(y, z)>0))暗示compare(x, z)>0.最后,实现者必须确保这
compare(x, y)==0意味着sgn(compare(x, z))==sgn(compare(y, z))对所有人而言z.
-1如果你的功能没有返回o1 < o2.它返回0,错误地断言参数是相等的.这也会导致第一个子弹失败:如果你翻转参数,结果需要改变符号.
正确的实施将是:
public int compare(Weight o1, Weight o2) {
return Integer.compare(o1.getWeight(), o2.getWeight());
}
Run Code Online (Sandbox Code Playgroud)
正如鲍里斯在评论中所说:你的compare()方法不正确.
看看你的实现:
return o1.getWeight() > o2.getWeight()? 1:0;
Run Code Online (Sandbox Code Playgroud)
假设您的列表中有三个对象:
现在假设以这种方式为您的列表sort()调用compare():
compare(o1, o2) 回报 0
compare(o2, o3) 回报 0
通过传递性,它意味着o1,o2并o3具有相同的顺序.你不想要我假设.
如果它适用于Java 6,它只是实现中的"机会"而不是你应该可靠的结果.
要解决您的问题,您必须处理3个案例(优等,劣等或相等):
@Override
public int compare(Weight o1, Weight o2) {
if (o1.getWeight() > o2.getWeight()){
return 1;
}
else if (o1.getWeight() < o2.getWeight()){
return -1;
}
return 0;
}
Run Code Online (Sandbox Code Playgroud)
这最终等同于写:return Integer.compare(o1.getWeight(), o2.getWeight()).
请注意,Java 8中更好的替代方案和更少的错误是使用Comparator.comparingInt()工厂方法并直接使用在以下sort()方法中引入的方法List:
weightList.sort(Comparator.comparingInt(Weight::getWeight));
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2594 次 |
| 最近记录: |