实现了Comparator的类在调用spliterator().getComparator时会产生IllegalStateException。

huangapple go评论76阅读模式
英文:

Class implementing Comparator produces IllegalStateException when probing spliterator().getComparator

问题

以下是翻译好的部分:

我有以下的类

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);
    }
}

现在我的理解是,以下的代码应该会产生一些类名或者null,而不会产生像Java文档中所述的IllegalStateException,文档中说:

如果这个 Spliterator 的源根据一个比较器进行了排序,返回该比较器。如果源是按自然顺序排序的,则返回null。否则,如果源未排序,则抛出IllegalStateException

List<A> arrayList = new ArrayList<>();
arrayList.add(new A("Y"));
arrayList.add(new A("G"));
arrayList.add(new A("J"));
arrayList.add(new A("A"));
arrayList.add(new A("Z"));

arrayList.sort(A::compareTo);
Comparator<? super A> comparator = arrayList.spliterator().getComparator();
System.out.println(comparator);

编辑2

我相信我可能没有办法让你理解我想要什么。以这个作为例子:

SortedSet<String> set = new TreeSet<>(Collections.reverseOrder());
set.add("A");
set.add("D");
set.add("C");
set.add("B");
System.out.println(set);
System.out.println(set.spliterator().getComparator());

这将输出:

[D, C, B, A]
java.util.Collections$ReverseComparator@7852e922

现在Collections.reverseOrder()只是一个比较器的实现。

既然这个例子产生了正确的答案,那么我对我的代码的期望也是它应该输出一个类名,就像上面的例子那样。

那么,我做错了什么?

英文:

I have following class

class A implements Comparable&lt;A&gt; {

    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);
    }
}

Now my understanding is that following code should produce some class name or null but not IllegalStateException as stated in the java document which says

> If this Spliterator's source is SORTED by a Comparator, returns that Comparator. If the source is SORTED in natural order, returns null. Otherwise, if the source is not SORTED, throws IllegalStateException.

List&lt;A&gt; arrayList = new ArrayList&lt;&gt;();
arrayList.add(new A(&quot;Y&quot;));
arrayList.add(new A(&quot;G&quot;));
arrayList.add(new A(&quot;J&quot;));
arrayList.add(new A(&quot;A&quot;));
arrayList.add(new A(&quot;Z&quot;));

arrayList.sort(A::compareTo);
Comparator&lt;? super A&gt; comparator = arrayList.spliterator().getComparator();
System.out.println(comparator);

EDIT 2

I believe i am not able to make you understand what i am looking for.
Take this as example:

SortedSet&lt;String&gt; set = new TreeSet&lt;&gt;( Collections.reverseOrder() );
set.add(&quot;A&quot;);
set.add(&quot;D&quot;);
set.add(&quot;C&quot;);
set.add(&quot;B&quot;);
System.out.println(set);
System.out.println(set.spliterator().getComparator());

This outputs as

[D, C, B, A]
java.util.Collections$ReverseComparator@7852e922

Now Collections.reverseOrder() is just an implementation of Comparator

Since this is producing the right answer, my expectation from my code is also it should output a class name like above.

So what is that I am not doing right ?

答案1

得分: 3

Spliterator的特性可能反映集合的当前内容,但通常仅取决于源集合的类型。因此,所有标准的List实现即使元素当前已排序,也从不报告SORTED特性,而所有SortedSet实现则始终报告SORTED特性。

您很少需要自己使用此方法。数据处理API(例如Stream API)可能会在幕后使用特性来优化执行。例如,Streamsorted操作在检测到数据已排序时可能会被跳过。但是以不太明显的示例来说明,当数据按元素类型的自然顺序排序时,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();
}
Type: class java.util.stream.ReferencePipeline$2
sorted: false

Type: class java.util.stream.ReferencePipeline$2
sorted: true

通常,您不会使用此API获取您自己创建的集合的比较器,因为您已经了解比较器。但是存在这样的情况,其中Spliterator具有不是直接来自您的代码的比较器:

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));
}
英文:

While the characteristics of a Spliterator may reflect the current contents of a collection, they are usually depending on the type of the source collection only. So all standard List implementations never report the SORTED characteristic, even when their elements happen to be currently sorted, whereas all SortedSet implementations always report the SORTED characteristic.

You may rarely need to use this method on your own. Data processing APIs, like the Stream API may use the characteristics behind the scenes, to optimize the execution. For example, the sorted operation of a Stream may get skipped when it detects that the data is already sorted. But to name a less obvious example, distinct may work differently when the data is sorted by the element type’s natural order.

Further, the state of a stream pipeline may serve as an example of a case, where the characteristics are not determined by the type:

public static void main(String[] args) {
    check(Stream.of(&quot;foo&quot;, &quot;bar&quot;).filter(x -&gt; true));
    check(Stream.of(&quot;foo&quot;, &quot;bar&quot;).sorted().filter(x -&gt; true));
}
private static void check(Stream&lt;?&gt; s) {
    System.out.println(&quot;Type: &quot;+s.getClass());
    System.out.println(&quot;sorted: &quot;+s.spliterator().hasCharacteristics(Spliterator.SORTED));
    System.out.println();
}

<!-- language: lang-none -->

Type: class java.util.stream.ReferencePipeline$2
sorted: false

Type: class java.util.stream.ReferencePipeline$2
sorted: true

Normally, you wouldn’t use this API to get the comparator of a collection you created yourself, as you already know the comparator. But there are cases where a spliterator has a comparator not originating from your code (directly):

TreeMap&lt;String, Integer&gt; map = new TreeMap&lt;&gt;(Comparator.comparingInt(String::length));

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

huangapple
  • 本文由 发表于 2020年4月6日 22:27:44
  • 转载请务必保留本文链接:https://go.coder-hub.com/61062111.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定