返回

工作中遇到的疑难问题:Comparison method violates its general contract! 异常

Android

java.util.TimSort.mergeHi() 异常:理解和解决

理解问题

在 Java 中,使用 java.util.Collections.sort() 方法对集合进行排序时,您可能会遇到 java.util.ConcurrentModificationException 异常,并伴随错误信息 "Comparison method violates its general contract! "。此异常表示比较方法违反了其通用契约。

什么是 TimSort 算法?

TimSort 是一种混合排序算法,结合了归并排序和插入排序的优点,在 Java 7 中引入。mergeHi() 方法是 TimSort 中用于合并两个已排序子数组的方法。

违反比较方法的通用契约

比较方法的通用契约定义了它应该如何比较两个对象:

  • 如果 o1 < o2,则返回一个负数
  • 如果 o1 = o2,则返回 0
  • 如果 o1 > o2,则返回一个正数

如果您的比较方法违反了此契约,例如返回与上述规则不一致的值,则会导致 java.util.ConcurrentModificationException 异常。

解决方法

解决此异常的最佳方法是确保您的比较方法正确实现了通用契约。以下是实现比较方法的两种常用方法:

1. 使用 Comparable 接口

如果您要比较具有自然排序顺序的对象(例如数字或字符串),则可以使用 Comparable 接口:

// 创建一个可比较的类
class MyComparable implements Comparable<MyComparable> {

    private int value;

    public MyComparable(int value) {
        this.value = value;
    }

    @Override
    public int compareTo(MyComparable other) {
        return Integer.compare(this.value, other.value);
    }
}

// 排序可比较对象
List<MyComparable> list = new ArrayList<>();
list.add(new MyComparable(1));
list.add(new MyComparable(2));
list.add(new MyComparable(3));
Collections.sort(list);

2. 使用 Comparator 类

如果您需要自定义排序顺序,可以使用 Comparator 类:

// 创建一个比较器
Comparator<Integer> comparator = new Comparator<Integer>() {
    @Override
    public int compare(Integer o1, Integer o2) {
        return o2 - o1; // 降序排序
    }
};

// 使用比较器排序
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
Collections.sort(list, comparator);

结论

java.util.ConcurrentModificationException: Comparison method violates its general contract! 异常表明您的比较方法违反了通用契约。通过确保您的比较方法正确实现,您可以解决此异常并对集合进行有效排序。

常见问题解答

  1. 什么是通用契约?
    通用契约是比较方法必须遵循的一组规则,以确保对象的排序方式一致且可预测。
  2. 如果我的比较方法使用的是 lambdas 表达式,该怎么办?
    在 lambdas 表达式中实现比较方法时,请确保该表达式遵循通用契约。
  3. 是否可以使用第三方库来排序集合?
    是的,有许多第三方库提供了排序功能,例如 Guava 或 Apache Commons Collections。
  4. 如何在异常中调试比较方法?
    可以在 mergeHi() 方法处设置断点,并检查对象的比较结果是否符合通用契约。
  5. 如何避免在多线程环境中发生此异常?
    在多线程环境中对集合进行排序时,请使用同步机制,例如 Collections.synchronizedList()