Java 类实现Comparator在探测spliterator()时生成IllegalStateException。getComparator

Java 类实现Comparator在探测spliterator()时生成IllegalStateException。getComparator,java,collections,spliterator,Java,Collections,Spliterator,我有以下课程 class A implements Comparable<A> { private String name; public A(String name) { this.name = name; } public String getName() { return name; } @Override public int compareTo(A o) { ret

我有以下课程

class A implements Comparable<A> {

    private String name;

    public A(String name) {
        this.name = name;
    }

    public String getName() {
       return name;
    }

    @Override
    public int compareTo(A o) {
        return o.getName().compareTo(this.name);
    }


    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        A a = (A) o;
        return name.equals(a.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name);
    }
}
现在Collections.reverseOrder只是Comparator的一个实现

由于这是正确的答案,我的代码期望它也能输出一个类似于上面的类名


那么,我做得不对的是什么呢?

虽然拆分器的特性可能反映集合的当前内容,但它们通常仅取决于源集合的类型。因此,所有标准列表实现从不报告已排序的特征,即使它们的元素恰好当前已排序,而所有SortedSet实现始终报告已排序的特征

您可能很少需要单独使用此方法。数据处理API(如流API)可以使用幕后的特性来优化执行。例如,当流检测到数据已排序时,可能会跳过流的排序操作。但举一个不太明显的例子,当数据按元素类型的自然顺序排序时,distinct的工作方式可能不同

此外,流管道的状态可作为一种情况的示例,其中特征不由类型决定:

public static void main(String[] args) {
    check(Stream.of("foo", "bar").filter(x -> true));
    check(Stream.of("foo", "bar").sorted().filter(x -> true));
}
private static void check(Stream<?> s) {
    System.out.println("Type: "+s.getClass());
    System.out.println("sorted: "+s.spliterator().hasCharacteristics(Spliterator.SORTED));
    System.out.println();
}
通常,您不会使用此API获取您自己创建的集合的比较器,因为您已经知道比较器。但在某些情况下,拆分器有一个比较器,而不是直接源于您的代码:

TreeMap<String, Integer> map = new TreeMap<>(Comparator.comparingInt(String::length));

Spliterator<Map.Entry<String, Integer>> sp = map.entrySet().spliterator();
if(sp.hasCharacteristics(Spliterator.SORTED)) {
    Comparator<? super Map.Entry<String, Integer>> comparator = sp.getComparator();
    System.out.println("Entry comparator: " + comparator);
    Map.Entry<String, Integer> e1 = new AbstractMap.SimpleEntry<>("some", 5);
    Map.Entry<String, Integer> e2 = new AbstractMap.SimpleEntry<>("string", 3);
    System.out.println(BinaryOperator.maxBy(comparator).apply(e1, e2));
}

虽然拆分器的特征可能反映集合的当前内容,但它们通常仅取决于源集合的类型。因此,所有标准列表实现从不报告已排序的特征,即使它们的元素恰好当前已排序,而所有SortedSet实现始终报告已排序的特征

您可能很少需要单独使用此方法。数据处理API(如流API)可以使用幕后的特性来优化执行。例如,当流检测到数据已排序时,可能会跳过流的排序操作。但举一个不太明显的例子,当数据按元素类型的自然顺序排序时,distinct的工作方式可能不同

此外,流管道的状态可作为一种情况的示例,其中特征不由类型决定:

public static void main(String[] args) {
    check(Stream.of("foo", "bar").filter(x -> true));
    check(Stream.of("foo", "bar").sorted().filter(x -> true));
}
private static void check(Stream<?> s) {
    System.out.println("Type: "+s.getClass());
    System.out.println("sorted: "+s.spliterator().hasCharacteristics(Spliterator.SORTED));
    System.out.println();
}
通常,您不会使用此API获取您自己创建的集合的比较器,因为您已经知道比较器。但在某些情况下,拆分器有一个比较器,而不是直接源于您的代码:

TreeMap<String, Integer> map = new TreeMap<>(Comparator.comparingInt(String::length));

Spliterator<Map.Entry<String, Integer>> sp = map.entrySet().spliterator();
if(sp.hasCharacteristics(Spliterator.SORTED)) {
    Comparator<? super Map.Entry<String, Integer>> comparator = sp.getComparator();
    System.out.println("Entry comparator: " + comparator);
    Map.Entry<String, Integer> e1 = new AbstractMap.SimpleEntry<>("some", 5);
    Map.Entry<String, Integer> e2 = new AbstractMap.SimpleEntry<>("string", 3);
    System.out.println(BinaryOperator.maxBy(comparator).apply(e1, e2));
}

ArrayList不记得它已被排序,也不保留对比较器的引用。因此,拆分器不具有排序特性。除此之外,不要使用::compareTo作为比较器。在对可比较元素列表调用sort时,请使用Comparator.naturalOrder或仅为null。您可以调用查找。当HasCharacteristicsOrdered返回true时,可以使用getComparator。没有理由不相信这种逻辑。在你的代码中,你没有检查它,但我已经在我的第一条评论中回答过,ArrayList不记得它已经被排序了。当然,这与树集完全不同,树集甚至会以保持排序的方式插入新元素,因此它准确地知道它已排序。@Slaw yes,Stream API的引用实现仅在拆分器有空比较器时,在排序无比较器的情况下消除冗余的排序操作。这种限制没有令人信服的理由。作者说,这是因为equals并不总是告诉你两个比较器在语义上是等价的,但对我来说,这并不是不这样做的理由,因为ArrayList不记得它已被排序,也不保留对比较器的引用。因此,拆分器不具有排序特性。除此之外,不要使用::compareTo作为比较器。在对可比较元素列表调用sort时,请使用Comparator.naturalOrder或仅为null。您可以调用查找。当HasCharacteristicsOrdered返回true时,可以使用getComparator。没有理由不相信这种逻辑。在你的代码中,你没有检查它,但我已经在我的第一条评论中回答过,ArrayList不记得它已经被排序了。当然,这与树集完全不同,树集甚至会以保持排序的方式插入新元素,因此它准确地知道它已排序。@Slaw yes,Stream API的引用实现仅在拆分器有空比较器时,在排序无比较器的情况下消除冗余的排序操作。这种限制没有令人信服的理由。作者说这是因为equals并不总是告诉你两个比较器在语义上是等价的,b 但对我来说,这并不是不这样做的理由。
TreeMap<String, Integer> map = new TreeMap<>(Comparator.comparingInt(String::length));

Spliterator<Map.Entry<String, Integer>> sp = map.entrySet().spliterator();
if(sp.hasCharacteristics(Spliterator.SORTED)) {
    Comparator<? super Map.Entry<String, Integer>> comparator = sp.getComparator();
    System.out.println("Entry comparator: " + comparator);
    Map.Entry<String, Integer> e1 = new AbstractMap.SimpleEntry<>("some", 5);
    Map.Entry<String, Integer> e2 = new AbstractMap.SimpleEntry<>("string", 3);
    System.out.println(BinaryOperator.maxBy(comparator).apply(e1, e2));
}