2017-01-09 12 views
6

Ich habe kürzlich über Streams in Java 8 gelernt und begann mit ihnen zu arbeiten. Jetzt habe ich eine Frage bezüglich der groupingBy Sammler Methode:Java 8 GroupingBy in Peek

Normalerweise ich mit .NET arbeiten, so verglich ich (zu wissen, sie sind nicht das gleiche) Java Stream<T> mit .NET IEnumerable<T>. Nach diesem Vergleich speichert List<T> Elemente und die jeweiligen Operationen. Ein Beispiel:

C#:

elements.Where(x => x.Value == 5).ToList(); 

Java:

elements.stream().filter(x -> x.getValue() == 5).collect(Collectors.toList()); 

In beiden Beispielen, beginne ich mit einer Liste definiert Operationen (ein Filter in diesem Beispiel) und sammeln das Ergebnis zu speichern es (in einer neuen Liste in diesem Beispiel).

Jetzt habe ich einen komplexeren Fall:

data.stream() 
    .map(...).filter(...) // Some operations 
    .collect(groupingBy(Chunk::getName, summingLong(Chunk::getValue))); 

Das Ergebnis dieser Abfrage ist eine Map<String, Long> und ich kann mit dieser Arbeit, aber sagen wir mal, ich mit dieser Daten fortfahren möchten anstatt es zu speichern. Mein aktueller Ansatz ist trivial:

... 
    .collect(groupingBy(Chunk::getName, summingLong(Chunk::getValue))) 
    .entrySet().stream(). 
    .map(...) // Do more operations 

Aber auf diese Weise, ich den Strom verlassen, speichern Sie das erste Ergebnis in einer Karte und öffnen einen neuen Stream fortzusetzen. Gibt es eine Möglichkeit, ohne einen Sammler zu gruppieren, so dass ich im Strom "bleiben" kann?

+1

Da Sie gruppieren, müssen Sie ziemlich viel zu einem Zwischenspeicher gehen - was, wenn Sie einen Wert am Anfang des Streams mit einem Wert am Ende gruppieren müssen? Sie müssten "alles" verarbeiten und speichern, bis Sie sicher sind, dass es nichts mehr zu gruppieren gibt. Also müsste Java (/ könnte?) Die Dinge auf eine Karte (oder eine ähnliche Struktur) stellen; Was ist so schlimm daran, das selbst zu tun? –

+0

Es ist nicht wirklich ein Problem, ich kann mit meinem trivialen Ansatz leben, aber in all meinen anderen Stream-Operationen gab es eine klare Grenze zwischen einer 'List' und einem' Stream'. Ich öffnete es, betätigte es und sammelte es. Jetzt gibt es eine Map, die für einen neuen Stream geöffnet wird, also habe ich mich gefragt, ob das mit einem anderen Ansatz möglich ist. –

+0

Vielleicht wurde ich von meinem .NET-Hintergrund verwirrt. Dort können Sie beliebige Operationen an einem 'IEnumerable' durchführen und am Ende sammeln Sie Ihr Ergebnis über' ToList', 'ToArray',' ToDictionary' oder indem Sie darüber iterieren. –

Antwort

4

Wie die API jetzt ist, können Sie nicht entkommen.

groupingBy

ist ein Terminal-Betrieb (es gibt keinen Stream), so dass der Betrieb wird der Strom beendet.

Je nachdem, was Sie später in der letzten Kartenoperation tun möchten, können Sie einen benutzerdefinierten Collector erstellen, der im Stream "bleibt". auch wenn in dir würde wahrscheinlich noch Elemente in eine Map sammeln.

+0

Gibt es irgendeine Kollektoroperation, die nicht Terminal ist? Wenn nicht, nehme ich an, das ist von Entwurf, also wäre es besser, manuell einen neuen Stream zu öffnen, habe ich recht? –

+1

@lukegv nein es ist nicht; Du hast recht. – Eugene

5

Sie können im nachgeschalteten Kollektor tun, was Sie wollen, solange Sie den Vorgang als Collector beschreiben können. Derzeit gibt es nur eine Entsprechung zu der Zwischenoperation map, der mapping Kollektor, aber Java 9 wird auch hinzufügen filtering und flatMapping (die Sie auch in Java 8 selbst implementieren könnten) und es gibt bereits ein Äquivalent zu fast jeder Terminaloperation.

Natürlich eine verschachtelte Gerät von Sammlern ganz anders aussehen als eine Kette von Stream-Operationen das gleiche tun ...

Wenn jedoch wollen Sie komplette Gruppen verarbeiten, gibt es keine Möglichkeit, die grouping Sammlung um Abschluss zuerst. Dies ist keine Einschränkung der API, aber für die Gruppierungsoperation oder eine Operation allgemein wichtig. Wenn Sie ein vollständiges Ergebnis verarbeiten möchten, müssen Sie zuerst die Operation abschließen. Unabhängig davon, wie die API aussieht, z.B. Sie könnten die Folgeoperation im Kollektor in einer collectingAndThen-ähnlichen Weise verstecken, das Erstellen und Bestücken des Map ist unvermeidlich, da es die Karte ist, die die Wartung der Gruppen durchführt.Die Gruppen werden durch die Schlüssel und die Nachschlagelogik des Map bestimmt, so dass z.B. Verwenden Sie eine SortedMap mit einem benutzerdefinierten Komparator oder IdentityHashMap, kann die Gruppierungslogik vollständig ändern.