JavaFx ObservableList<String> sorted()与sorted(Comparator.<String>naturalOrder())有什么区别?

4
所以我最初尝试使用


listOfStrings = listOfStrings.sorted();


Ordering user11, user10, user20, user04 etc...

这段文字提到了 JavaDoc,其中说明它将创建一个具有自然排序的列表。

用户抱怨排序有问题,因此我认为需要编写比较器,但幸运的是,IntelliJ自动填充了代码。

listOfStrings = listOfStrings.sorted(Comparator.<String>naturalOrder());

Ordering user01, user02, user03, user04 etc...

我的第一反应是它会返回相同的内容,但它按照我想要的方式对字符串进行排序。 Comparator.naturalOrder 的文档也涉及到自然顺序

那么我在文档中错过了什么?

我的阅读文档的理解是它们应该以相同的顺序排序列表。有人明白为什么它们不这样做吗?

从文本文件中读取字符串,作为哈希映射中的键:user01,user02,user03.user04,user05,user06,user07,user08,user09,user10,user11,user12,user13,user14,user15,user16, user17,user18,user19,user20。

for (String user: userMap.keySet()) {
            listOfStrings.add(user);
}  

// listOfStrings = listOfStrings.sorted();  //
listOfStrings = listOfStrings.sorted(Comparator.<String>naturalOrder());

你能举个两种不同排序方案的例子吗? - durron597
你能否提供一个可重现的例子,以便在结果不同时进行排查? - Paul Boddington
2个回答

4
这是Java 8u40中的一个错误,后来的版本已经(大多数情况下)进行了修复。 (有关边缘案例或备选实现选择的讨论,请参见此答案的评论)。错误跟踪问题为: 并且有相关变更集

Java 8u40 codeObservableList.java 的代码为:

public default SortedList<E> sorted() {
    return sorted(null);
}

上述调用的错误调用顺序在用户pbabcdefp的答案中详细说明。代码中的错误基本上意味着sorted()方法根本不返回排序后的列表,而是以当前顺序返回列表。 Java 8u-dev(当前主干代码)和Java 9u-dev代码如下:
/**
 * Creates a {@link SortedList} wrapper of this list with the natural
 * ordering.
 * @return new {@code SortedList}
 * @since JavaFX 8.0
 */
public default SortedList<E> sorted() {
    Comparator naturalOrder = new Comparator<E>() {

        @Override
        public int compare(E o1, E o2) {
            if (o1 == null && o2 == null) {
                return 0;
            }
            if (o1 == null) {
                return -1;
            }
            if (o2 == null) {
                return 1;
            }

            if (o1 instanceof Comparable) {
                return ((Comparable) o1).compareTo(o2);
            }

            return Collator.getInstance().compare(o1.toString(), o2.toString());
        }
    };
    return sorted(naturalOrder);
}

感谢您找到了错误跟踪器。即使新版本对我来说看起来有点不可靠。除了使用原始类型之外,它甚至不对称。如果 EObjecto1"Foo"o2new Object(),那么 compare(o1, o2) 将抛出 ClassCastException,而 compare(o2, o1) 将比较 toString 表示。if(o1 instanceof Comparable && o2 instanceof Comparable) 更合乎逻辑。 - Paul Boddington
我的问题是,他们不能只使用Comparator.<String>naturalOrder()来修复它吗?就像我做的那样,而不是重写它? - Travis
Travis,我建议你在JavaFX问题跟踪器中创建一个新问题,让开发人员查看一下,看看是否应该实现更优秀的解决方案,沿着pbabcdefp或你自己建议的方向 - 你可以从问题报告中链接回这个stackoverflow问题。 - jewelsea
@ pbabcdefp:当EObjecto1的类型为Fooo2new Object()时,在哪一行你认为会发生ClassCastException?两个参数值最终都是类型为Object - Ben

2
我的理解是,在两次调用中应该得到相同的顺序,这也是文档的意思。但是通过查看源代码,我发现了以下内容。
下面是ObservableList.sorted()的源代码。
public default SortedList<E> sorted() {
    return sorted(null);
}

这里是被调用的方法。

public default SortedList<E> sorted(Comparator<E> comparator) {
    return new SortedList<>(this, comparator);
}

这里是相关构造函数的文档。
public SortedList(ObservableList<? extends E> source,
              Comparator<? super E> comparator)

Creates a new SortedList wrapped around the source list. The source list will be sorted using the comparator provided. If null is provided, the list stays unordered and is equal to the source list.

据我所知,代码与文档矛盾,除非 ObservableList 的实现覆盖了相关的默认方法。非常奇怪。这一定是一个错误,肯定是吧?

我一开始也以为这是个bug,但通常像Java这样广泛使用的工具,我发现我经常会误解某些东西。 - Travis
1
@Travis。我也是。在添加最后一句之前,我犹豫了。这确实非常奇怪。 - Paul Boddington

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接