Android: 比较方法违反了它的一般契约
Android: Comparison method violates its general contract
我发现我的应用程序在某些中国 Android 手机上经常崩溃,并出现错误:比较方法违反了它的一般合同!
我了解到这与 Collections.sort 调用有关。
我不太确定是不是因为我的自定义比较器。
这里是错误发生的地方:
if (!airports.isEmpty()) {
Collections.sort(airports, new DistanceToAirportComparator(location));
return airports.get(0);
}
比较器看起来像这样:
public class DistanceToAirportComparator implements Comparator<Airport> {
private final Location location;
public DistanceToAirportComparator(Location location) {
this.location = location;
}
@Override
public int compare(Airport airport1, Airport airport2) {
Location loc1 = getLocation(airport1);
Location loc2 = getLocation(airport2);
return Double.compare(location.distanceTo(loc1), location.distanceTo(loc2));
}
private Location getLocation(Airport airport){
Location location = new Location(LocationManager.GPS_PROVIDER);
location.setLatitude(airport.getLocation().getLatitude());
location.setLongitude(airport.getLocation().getLongitude());
return location;
}
所以我不太确定比较器是否搞砸了,或者我是否需要以不同的方式进行 collections.sort 调用
感谢任何帮助
异常是这样说的:
比较器应该是正确的,因为如果 A > B 且 B > C,则 A > C 必须为真。
所以,归结为为什么会出现这样的问题。
我的猜测是,由于 Location 的性质,距离的计算是 unstable
我建议您预先计算距离并对结果使用比较器。
编辑:
示例
private Airport sortByDistance(Location location) {
List<Airport> airports;
if (!airports.isEmpty()) {
ArrayList<AirportWithDistance> distanceArrayList = new ArrayList<AirportWithDistance>(airports.size());
for (Airport airport : airports) {
distanceArrayList.add(new AirportWithDistance(airport, getDistance(airport, location)));
}
// replace start
Collections.sort(distanceArrayList, new DistanceToAirportComparator());
return airports.get(0).airport;
// replace end
//also seems u should replace the above to the line below instead, as you only wan min
//return Collections.min(distanceArrayList, new DistanceToAirportComparator()).airport;
}
return null;
}
private static double getDistance(Airport airport, Location location){
Location airportLocation = new Location(LocationManager.GPS_PROVIDER);
airportLocation.setLatitude(airport.getLocation().getLatitude());
airportLocation.setLongitude(airport.getLocation().getLongitude());
return location.distanceTo(airportLocation);
}
public static class AirportWithDistance {
Airport airport;
double distance;
AirportWithDistance(Airport airport, double distance) {
this.airport = airport;
this.distance = distance;
}
}
public static class DistanceToAirportComparator implements Comparator<AirportWithDistance> {
public DistanceToAirportComparator() {
}
@Override
public int compare(AirportWithDistance airport1, AirportWithDistance airport2) {
return Double.compare(airport1.distance, airport2.distance);
}
}
我发现我的应用程序在某些中国 Android 手机上经常崩溃,并出现错误:比较方法违反了它的一般合同!
我了解到这与 Collections.sort 调用有关。
我不太确定是不是因为我的自定义比较器。
这里是错误发生的地方:
if (!airports.isEmpty()) {
Collections.sort(airports, new DistanceToAirportComparator(location));
return airports.get(0);
}
比较器看起来像这样:
public class DistanceToAirportComparator implements Comparator<Airport> {
private final Location location;
public DistanceToAirportComparator(Location location) {
this.location = location;
}
@Override
public int compare(Airport airport1, Airport airport2) {
Location loc1 = getLocation(airport1);
Location loc2 = getLocation(airport2);
return Double.compare(location.distanceTo(loc1), location.distanceTo(loc2));
}
private Location getLocation(Airport airport){
Location location = new Location(LocationManager.GPS_PROVIDER);
location.setLatitude(airport.getLocation().getLatitude());
location.setLongitude(airport.getLocation().getLongitude());
return location;
}
所以我不太确定比较器是否搞砸了,或者我是否需要以不同的方式进行 collections.sort 调用
感谢任何帮助
异常是这样说的:
比较器应该是正确的,因为如果 A > B 且 B > C,则 A > C 必须为真。
所以,归结为为什么会出现这样的问题。 我的猜测是,由于 Location 的性质,距离的计算是 unstable
我建议您预先计算距离并对结果使用比较器。
编辑:
示例
private Airport sortByDistance(Location location) {
List<Airport> airports;
if (!airports.isEmpty()) {
ArrayList<AirportWithDistance> distanceArrayList = new ArrayList<AirportWithDistance>(airports.size());
for (Airport airport : airports) {
distanceArrayList.add(new AirportWithDistance(airport, getDistance(airport, location)));
}
// replace start
Collections.sort(distanceArrayList, new DistanceToAirportComparator());
return airports.get(0).airport;
// replace end
//also seems u should replace the above to the line below instead, as you only wan min
//return Collections.min(distanceArrayList, new DistanceToAirportComparator()).airport;
}
return null;
}
private static double getDistance(Airport airport, Location location){
Location airportLocation = new Location(LocationManager.GPS_PROVIDER);
airportLocation.setLatitude(airport.getLocation().getLatitude());
airportLocation.setLongitude(airport.getLocation().getLongitude());
return location.distanceTo(airportLocation);
}
public static class AirportWithDistance {
Airport airport;
double distance;
AirportWithDistance(Airport airport, double distance) {
this.airport = airport;
this.distance = distance;
}
}
public static class DistanceToAirportComparator implements Comparator<AirportWithDistance> {
public DistanceToAirportComparator() {
}
@Override
public int compare(AirportWithDistance airport1, AirportWithDistance airport2) {
return Double.compare(airport1.distance, airport2.distance);
}
}