2015-07-01 10 views
6

Nach dem doc von Spliterator#getComparator wirft, heißt esgibt es den spliterator aus einem sortierten Strom eine Ausnahme

Wenn dieser Spliterator der Quelle SORTED durch ein Comparator ist, kehrt die Comparator. Wenn die Quelle SORTED in natürlicher Reihenfolge ist, wird null zurückgegeben. Andernfalls, wenn die Quelle nicht SORTED ist, wird IllegalStateException ausgelöst. Anforderungen

Umsetzung:

Die Standardimplementierung immer wirft IllegalStateException.

Rückgabe: a Comparator oder null wenn die Elemente in der natürlichen Reihenfolge sortiert sind.

Wirf: IllegalStateException - wenn der Spliterator keine Eigenschaft von SORTED meldet.

Also, wenn Sie dieses Stück Code ausgeführt

Spliterator<Integer> spliterator = Stream.of(1, 2, 3).sorted().spliterator(); 

System.out.println((spliterator.characteristics() & Spliterator.SORTED) == Spliterator.SORTED); 
System.out.println(spliterator.getComparator()); 

ich:

true 
null 

So weit so gut. Nun, wenn dies zu tun:

Spliterator<Integer> spliterator = Stream.of(1, 2, 3).sorted(Comparator.naturalOrder()).spliterator(); 

System.out.println((spliterator.characteristics() & Spliterator.SORTED) == Spliterator.SORTED); 
System.out.println(spliterator.getComparator()); 

Es gibt false und löst eine Ausnahme:

Exception in thread "main" java.lang.IllegalStateException 
    at java.util.stream.StreamSpliterators$AbstractWrappingSpliterator.getComparator(StreamSpliterators.java:259) 
    at SpliteratorTest.main(SpliteratorTest.java:10) 

Warum ist es falsch ausgibt und löst eine Ausnahme?

Sollte es mir nicht die Comparator geben, die ich sorted() gemäß der Dokumentation lieferte?

(Dies geschieht auch mitoder comparing(identity()), usw.).

+3

Übrigens können Sie 'spliterator.hasCharacteristics (Spliterator.SORTED)' – Holger

+0

verwenden Ich fand eine [verwandte Diskussion] (http://mail.openjdk.java.net/pipermail/core-libs-dev/2014 (Juni/027421.html) in den Mail-Archiven, aber ich bin nicht von [Paul Santoz 'Antwort] überzeugt (http://mail.openjdk.java.net/pipermail/core-libs-dev/2014-June/027423) .html). Warum würde ein Stream aus einem 'TreeSet' mit einem benutzerdefinierten Komparator' SORTED' sein und ein Stream, der mit demselben benutzerdefinierten Vergleicher sortiert ist, nicht? –

+0

@Didier L: Das ist in der Tat nicht überzeugend. Vor allem das "wir wissen nicht, ob zwei Komparatoren in ihrem Verhalten identisch sind" -Teil. Natürlich könnte es zwei verschiedene Komparatoren geben, die das gleiche Verhalten zeigen, ohne eine Möglichkeit, sie zu erkennen, aber das ist kein Grund, die Tatsache zu ignorieren, dass zwei identische Komparatoren natürlich das gleiche Verhalten zeigen. Insbesondere, da beide, Comparator.naturalOrder() = Comparator.naturalOrder() und Comparator.reverseOrder() = Comparator.reverseOrder(), zu "true" auswerten. – Holger

Antwort

1

Interne Streams verwenden StreamOpFlag Enum, die etwas von Spliterator Flags unterscheidet. Flags werden unter Verwendung der Methode java.util.stream.StreamOpFlag.fromCharacteristics(Spliterator<?>) die umgewandelt Umsetzung ist die folgende:

static int fromCharacteristics(Spliterator<?> spliterator) { 
    int characteristics = spliterator.characteristics(); 
    if ((characteristics & Spliterator.SORTED) != 0 && spliterator.getComparator() != null) { 
     // Do not propagate the SORTED characteristic if it does not correspond 
     // to a natural sort order 
     return characteristics & SPLITERATOR_CHARACTERISTICS_MASK & ~Spliterator.SORTED; 
    } 
    else { 
     return characteristics & SPLITERATOR_CHARACTERISTICS_MASK; 
    } 
} 

Es scheint, dass die intern SORTED Kennlinie für den spliterator die für den Stream API nicht explizit natürlich geordnete nicht notwendig ist, so ist es nicht konserviert. Tatsächlich ist es nie in der Dokumentation angegeben, dass sorted(comparator).spliterator() den Spliterator mit SORTED Eigenschaft zurückgeben muss. Die Spliterator-Dokumentation sagt, dass, wenn es SORTED Eigenschaft hat, muss es den Komparator zurückgeben, aber es gibt keinen Fall, wenn das SORTED Merkmal erforderlich ist, also ist es bis zur Implementierung. Das kann sich in Zukunft ändern, aber es ist kein Fehler.

Update: habe gerade bemerkt, dass in JDK-9 gibt es eine klare Aussage added in die Dokumentation von spliterator() Methode:

Der zurück spliterator die Reihe von Merkmalen aus dem Stream-Pipeline abgeleitet berichten sollte (nämlich die Eigenschaften, die von dem Stromquellen-Spliterator und den Zwischenoperationen abgeleitet sind). Implementierungen können eine Untergruppe dieser Merkmale melden. Zum Beispiel kann es zu teuer sein, das gesamte Set für einige oder alle möglichen Stream-Pipelines zu berechnen.

Siehe JDK-8048689 Fehlerbericht.

+1

Ich würde nicht sagen, dass die Eigenschaft 'SORTED' für die Stream-API * unnötig ist, wenn ein Komparator verwendet wird, es ist nur ein großer Fehler der aktuellen Implementierung, dass die Verwendung von expliziten Komparatoren als Sortierung zweiter Klasse behandelt wird. Selbst die Verwendung von 'Comparator.naturalOrder()' kann einen Leistungsabfall über die Verwendung von 'sorted()' ohne Vergleicher (und ohne Kompilierungszeitsicherheit) haben ... – Holger

+1

@Holger, ich meine, für die aktuelle Implementierung ist das unnötig. Sicherlich muss die Implementierung zumindest verbessert werden, um 'Comparator.naturalOrder()' zu erkennen. –

0

Ich denke, das ist ein Fehler in Oracle JDK (1.8.0_45).

Wenn Sie einen Stream machen mit Stream#sorted() natürlichen Reihenfolge sortiert verwenden, wickelt es intern den Strom in einem SortedOps.OfRef den folgenden Konstruktor:

OfRef(AbstractPipeline<?, T, ?> upstream) { 
     super(upstream, StreamShape.REFERENCE, 
       StreamOpFlag.IS_ORDERED | StreamOpFlag.IS_SORTED); 
    ... 

Wenn Sie eine benutzerdefinierte Comparator mit Stream#sorted(Comparator) geben, tut es das gleiche sondern verwendet den folgenden Konstruktor statt:

OfRef(AbstractPipeline<?, T, ?> upstream, Comparator<? super T> comparator) { 
     super(upstream, StreamShape.REFERENCE, 
       StreamOpFlag.IS_ORDERED | StreamOpFlag.NOT_SORTED); 
    ... 

die StreamOpFlag.NOT_SORTED soll die SORTED fl löschen ag, falls es vorher eingestellt wurde. Dies bedeutet, dass ein sortierter Stream nach dieser Operation zu einem nicht sortierten Stream wird.

Ich denke, es könnte anstelle von StreamOpFlag.IS_SORTED und der super() Aufruf sollte die gleichen Parameter wie im ersten Konstruktor verwendet werden.

Ich konnte jedoch kein entsprechendes Problem im Java Bug System finden.

Verwandte Themen