2014-04-01 3 views
9

ich die Java-8-Streams Gedanken über (Stream<E>), haben sie die folgenden Methoden:Was sind die Gründe dafür, keinen Index in Java 8 Streams zu haben?

  • forEach(Consumer<? super E> action)
  • forEachOrdered(Consumer<? super E> action)

Was die Argumente waren gegen nicht die folgende Signatur liefert?

  • forEachOrdered(BiConsumer<Integer, ? super E> action)
    • die dann den Index des Elements in dem Strom und dem Punkt zurückkehren würde sich.

Mit dieser Überlastung wäre es möglich, tatsächlich den Index zu verwenden, falls der Strom bestellt wurde.

Ich bin wirklich gespannt, was die Argumente dagegen sind.

Bearbeiten, das gleiche gilt auch für Iterator<E> mit forEachRemaining, und möglicherweise weitere Klassen.
Wenn keine der Klassen eine solche Option bietet, vermute ich, dass sie für Java 8 in Betracht gezogen und abgelehnt wurde.

+0

http://stackoverflow.com/a/18563928/829571 – assylias

+0

@assylias Danke für den Stecker. Das veranlasste mich, diese Antwort aufzuräumen. :-) –

Antwort

5

Stream s und Iterator s müssen nicht endlich sein. Beide Stream::generate und Stream::iterate Rückkehr unendlich Stream s. Wie würden Sie mit der Indizierung mit einem unendlichen Stream umgehen? Lassen Sie den Index zu negativen Zahlen überlaufen? Verwenden Sie eine BigInteger (und möglicherweise nicht genügend Arbeitsspeicher)?

Es ist keine gute Lösung, die Indizierung für unendliche Strom Handhabung, so die Designer (richtig, meiner Meinung nach) beließ es aus der API.

+3

Das gleiche Problem tritt bei 'Collectors.counting()' auf, dort wird ein 'long' verwendet, aber es kann auch überlaufen. In diesem Punkt ist entweder Ihr Argument nicht gut genug oder es ist ein gutes Argument gegen 'Collectors.counting()'. Ich sehe jedoch keine anderen Probleme mit unendlichen Streams und Iteratoren (abgesehen davon, dass sie nie aufhören) – skiwi

+1

@skiwi Nun, wenn Sie versuchen würden, die Hälfte der Methoden in 'Collectors' auf einen unendlichen' Stream' zu verwenden, würden Sie entweder ausgehen von Speicher oder führen Sie eine Endlosschleife ein. 'Collectors' bietet Utility-Methoden für die meisten Anwendungsfälle. Die meiste Zeit wirst du nicht mit einem unendlichen "Stream" zu tun haben, also ist "Collectors" gerechtfertigt. – Jeffrey

8

Indizieren jedes Element erfordert eine sequentielle Zuordnung der Indizes. Dies würde den Punkt der parallelen Operationen zunichte machen, da jede Operation synchronisiert werden müsste, um ihren Index zu erhalten.

+0

+1. Indizes sind für parallele Streams unsinnig. –

+1

Ich spreche speziell über geordnete Ströme, wenn Sie sich entscheiden, bei Ihrer Antwort zu bleiben, können Sie erklären, warum es nicht möglich ist, in einem parallel geordneten Strom zu indizieren? – skiwi

+0

Wenn Sie möchten, können Sie einen Zähler im Kunden selbst für Operationen halten, von denen bekannt ist, dass sie in der Reihenfolge ausgeführt werden. Warum brauchen Sie also die zusätzliche Signatur? –

2

Das Hinzufügen einer einzelnen Methode, die einen Index zur Verfügung stellt, würde erfordern, alle Implementierungen Methoden verdoppelt werden, um einen zu haben, der einen Index und einen ohne aufrechterhält. Es ist mehr als nur in der API sichtbar. Wenn Sie neugierig sind, können Sie den Typbaum der internen Schnittstelle java.util.stream.Sink<T> betrachten, um eine Idee zu bekommen. Alle wären betroffen. Die Alternative wäre, einen Index immer zu pflegen, auch wenn er nicht benötigt wird.

Und es fügt eine Mehrdeutigkeit hinzu. Hat der Index spiegelt den Quelle Index, das heißt nicht ändert, auf Filtern, oder ist es eine Position im Endstrom? Auf der anderen Seite können Sie immer ein Mapping von einem Elementtyp in einen Typ einfügen, der das Element und einen Index an beliebigen Stellen in der Kette enthält. Dies würde die Mehrdeutigkeit beseitigen. Und die Einschränkungen für diese Lösung sind die gleichen, die eine von JRE bereitgestellte Lösung hätte.

Im Fall einer Iterator die Antwort ist noch einfacher. Da forEachRemaining als Schnittstellenmethode default bereitgestellt werden muss, kann die Pflege eines Indexes nicht hinzugefügt werden.Zu dem Zeitpunkt, zu dem es aufgerufen wird, weiß es nicht, wie viele Artikel bisher verbraucht wurden. Würde man zu diesem Zeitpunkt die Zählung mit Null beginnen, wäre das Ignorieren aller vorherigen Elemente ein Merkmal, das viele Entwickler noch mehr in Frage stellen würden.

0

Ich habe alle obigen Antworten gelesen, aber ich persönlich stimme nicht mit ihnen überein. Ich denke, dass eine Methode (z. B. indexed()) hinzugefügt werden sollte, und es kann sequenziell ausgeführt werden, auch im parallelen Datenstrom, da diese Methode schnell verifiziert werden, keine Notwendigkeit, parallel ausgeführt werden. Sie können 'Index' nach Karte hinzufügen. zum Beispiel:

List<String> list = N.asList("a", "b", "c"); 
final AtomicLong idx = new AtomicLong(0); 
list.stream().map(e -> Indexed.of(idx.getAndIncrement(), e)).forEach(N::println); 

Oder können Sie dritte Bibliothek verwenden: AbacusUtil, wird der Code sein:

List<String> list = N.asList("a", "b", "c"); 
Stream.of(list).indexed().forEach(N::println); 
// output: 
// [0]=a 
// [1]=b 
// [2]=c 

Disclosure: Ich bin der Entwickler AbacusUtil.

Verwandte Themen