当用于比较对象的所选字段相等时,Java 如何决定对具有多个字段的对象列表进行排序?

How does Java decide to sort a list of objects with multiple fields, when the chosen field to compare the object is equal?

我有一个名为 Instance 的对象,它有 2 个字段,一个特征数组(这是另一个对象),代表数据集中的列,例如年龄、性别、class 等;以及它们的值(即一个数字)。我还实现了一个自定义比较器,它可以根据实例的特定功能对这些对象的列表进行排序,如下所示:

Comparator<Instance> comparator = Comparator.comparing(c -> c.get(feature));
Instance[] sorted = instList.stream().sorted(comparator).toArray(Instance[]::new);

现在,这段代码工作正常,但是,在很多情况下,我排序所依据的特征与另一个实例具有相同的值。在这种情况下,Java如何决定如何继续对列表进行排序?

引用 Java API for Stream.sorted():

For ordered streams, the sort is stable. For unordered streams, no stability guarantees are made.

List 上的流使用 , which means a stable 排序算法。稳定排序保证相等的元素不会被交换。比较相等的元素以与起始列表中相同的相对顺序保留。

标准库中的所有排序方法都有类似的保证:

  • Collections.sort()

  • Arrays.sort()

  • Arrays.parallelSort()

    This sort is guaranteed to be stable: equal elements will not be reordered as a result of the sort.

    ...

    The documentation for the methods contained in this class includes briefs description of the implementations. Such descriptions should be regarded as implementation notes, rather than parts of the specification. Implementors should feel free to substitute other algorithms, so long as the specification itself is adhered to. (For example, the algorithm used by sort(Object[]) does not have to be a MergeSort, but it does have to be stable.)

  • List.sort()

    Implementation Note:
    This implementation is a stable, adaptive, iterative mergesort...

sex

除非您有特殊原因,否则不要提出要求(不仅出于普遍的善意,而且因为不必要的要求意味着您的申请可能很快无法用于欧盟政府业务。不妨加入忘记这个的习惯)。

In this case, how does Java decide how to continue sorting the list?

如果考虑 2 个对象 'on equal footing',那么会发生什么取决于你在做什么。

对于 Collections.sortArrays.sort、流和任何其他不能保证唯一性的东西 属性,排序顺序或多或少在这两者之间 'arbitrary' .

对于像 TreeSet 这样的独特概念,'on equal footing' 意味着相等,并且没有 2 个项目 'on equal footing' 可以在同一个树集中。

I have an object called Instance with 2 fields

请注意,您可以链接比较器:如果比较器不能区分两个对象,您可以告诉它使用另一个比较器:

Comparator<Instance> comparator = Comparator.comparingInt(Instance::getAge)
  .thenComparing(Comparator.comparing(Instance::getKind));