2016-09-26 3 views
8

Gegeben ich habe einen Stream Stream<T> stream = list.stream().filter(some predicate) wo die Liste sehr groß ist, ist es effizienter zu überprüfen, ob der Stream nicht leer ist, indem Sie: stream.count() > 0 oder indem Sie: stream.findFirst().isPresent()?Ist Java 8 findFirst(). IsPresent() effizienter als count()> 0?

+0

Es hängt davon ab, welche 'List'-Implementierung es ist, aber es ist nicht einmal vergleichbar, da es Sie im Stream bewegt. – EJP

+6

Bei unendlichen Streams endet 'count()' nicht einmal; selbst für endliche Ströme muss es den gesamten Strom durchlaufen, bevor es zurückkehrt. Während 'findFirst()' oder 'findAny()' oder 'anyMatch (e -> true)' kurzgeschlossen sind, hören sie auf, wenn sie ein Element finden. –

+3

Die wahre Lektion hier ist, dass die richtige Frage nicht die Effizienz, sondern die Korrektheit ist. Die Verwendung von 'findXxx' oder' xxxMatch' ist besser, nicht weil sie effizienter sind, sondern weil sie näher an der Eigenschaft sind, die Sie eigentlich kennen möchten. Dass sie effizienter sind, ist lediglich ein angenehmer Nebeneffekt der besseren Abfrage der Bibliothek. –

Antwort

5

Wenn alles, was Sie wissen wollen, ist, ob es eine Übereinstimmung gibt, sollen Sie
list.stream().anyMatch(some predicate), nicht nur weil es effizienter ist, sondern auch, weil es das richtige Idiom ist, dass Sie die Absicht zum Ausdruck.

von anderen Wie gesagt, anyMatch Kurzschlüsse, die, dass es bedeutet, im ersten Spiel zu stoppen, während count wird, wie der Name schon vor der Rückkehr, zählt alle Matches vermuten läßt. Abhängig vom Stream-Inhalt kann dies einen enormen Leistungsunterschied bewirken. Aber beachten Sie, dass Sie count ähnlich effizient machen, durch die Verwendung list.stream().filter(some predicate).limit(1).count() > 0

Dann wird es auch nach dem ersten Auftreten zu stoppen, aber, wie gesagt, anyMatch ist nach wie vor die bevorzugte Art und Weise zum Ausdruck bringt, dass Sie sich, ob es Interesse ist irgendein Spiel. Dinge ändern sich, wenn die Aufgabe ist herauszufinden, ob es mindestensn Übereinstimmungen gibt. Dann wird .limit(n).count() > n-1 (oder >= n) das natürliche Idiom.

Beachten Sie, dass findFirst() sich von der anderen Lösung unterscheidet, da ihre Antwort von der Bestellung abhängt. Wenn Sie also nur wissen wollen, ob es eine Übereinstimmung gibt, sollten Sie stattdessen findAny() verwenden. Dennoch gibt es einen theoretischen Unterschied aufgrund der Anforderung, den übereinstimmenden Wert zurückzugeben, verglichen damit, nur zu sagen, ob es eine Übereinstimmung gibt, wie anyMatch, obwohl dieser Unterschied derzeit nur in der Konstruktion einer Optional Instanz liegt, daher vernachlässigbar ist.

Aber da Sie gegen eine API programmieren, um Ihre Absicht zu kodieren, sollten Sie nicht find… verwenden, wenn Sie nur wissen wollen, ob es eine Übereinstimmung gibt. anyMatch drückt Ihre Absicht deutlich aus und könnte in zukünftigen Implementierungen oder komplexeren Szenarien einen noch höheren Nutzen haben.

11

Ich würde empfehlen, list.stream().anyMatch(some predicate), die eine Terminal-Operation für genau diesen Fall ist. Es ist nicht nur effizienter als stream.count(), aber es wird nicht auf unendlichen Streams hängen.

+1

good point of, an unendlichen strömen hängen! –

+0

@Holger Es klingt, als ob du mit etwas nicht einverstanden bist, was ich gesagt habe. – shmosel

+0

Vielleicht habe ich gestern in Ihrer Antwort etwas falsch verstanden, ich denke, ich habe das "nur" übersehen ... Ich habe nicht runtergestimmt, falls Sie sich fragen. – Holger

2

findAny (die findFirst vorzuziehen ist, wenn Sie benötigen Bestellung nicht) und anyMatch sind short-circuiting operations, das heißt, sie können früh zurückzukehren, ohne den gesamten Strom aufwendig, wenn es die Bedingungen erlauben. Dies wird in ihrer Methode javadocs erwähnt und verknüpft. count()is not. kann dann count() so schnell sein wie die beiden anderen Optionen

Wenn die letzte Stufe der Strom noch eine spliterator mit dem SIZED Charakteristik verwendet. Dies ist jedoch eine viel schwächere Eigenschaft als ein Kurzschluss, da Zwischenstromprozesse - wie filter() - sehr wahrscheinlich den SIZED-Aspekt verwerfen.

All diese Informationen können aus der Paketdokumentation entnommen werden, es wird dringend empfohlen, zu lesen.

+1

Da der Code der Frage eine 'Filter'-Operation enthält, gibt es keine Möglichkeit, jedes Element zu testen, um die Anzahl der übereinstimmenden Elemente zu erhalten. Abgesehen davon, dass der Hotspot-Optimierer (in einem sequenziellen Kontext) erkennen könnte, dass die Berechnung der Anzahl nicht notwendig ist, da die resultierende Zahl verwendet wird. In jedem Fall ist "count" die schlechteste Wette. – Holger

+0

@Holger Ich habe nicht anders behauptet. Ich wollte nur erwähnen, dass "Count" unter begrenzten Umständen genauso schnell sein kann. Eine denkbare Optimierung wäre etwas wie ein '.filter (Predictate.TRUE)' (wenn es existiert), das den Quell-Spliterator bewahrt. – the8472

+2

Ich wollte nur erwähnen, dass die Umstände, unter denen eine vorhersehbare Größe verfügbar sein könnte, gut bekannt sind (weshalb ich es von meiner Antwort wegließ, da es hier nicht anwendbar ist), und ein Prädikat "immer" existiert nicht , die vielleicht nicht so dramatisch, aber noch schlimmer ist, in Oracles JRE/OpenJDK wird die bekannte Zahl von 'SIZED'-Spliteratoren erst verwendet, nachdem Java 9 ... – Holger

Verwandte Themen