2014-12-20 3 views
8

Mein genaues Szenario ist das Einfügen von Daten in die Datenbank in Stapeln, also möchte ich DOM-Objekte dann alle 1000 akkumulieren, flush sie.Gibt es eine elegante Möglichkeit, einen Stream in Chunks zu verarbeiten?

Ich implementierte es, indem ich Code in den Akku legte, um Fülle zu erkennen, dann flush, aber das scheint falsch - die Flush-Steuerung sollte vom Anrufer kommen.

Ich könnte den Stream in eine Liste konvertieren dann SubList in einer iterativen Weise verwenden, aber das scheint auch klobig.

Es gibt einen netten Weg, um alle n Elemente zu handeln dann mit dem Stream weiter, während nur den Stream einmal verarbeiten?

+2

Für einen ähnlichen Anwendungsfall ich dies tat: https://bitbucket.org/assylias/bigblue-utils/src/3f56d19777a0ebc5dc3b53d3c2ec8dc64fd2b28e/src/main/java/com/assylias/bigblue/utils/SplitProcessing.java?at= Meister - nicht genau das, wonach du fragst. – assylias

Antwort

4

Eleganz liegt im Auge des Betrachters. Wenn Sie nicht in groupingBy mit einer Stateful-Funktion dagegen haben, können Sie dies tun:

AtomicInteger counter = new AtomicInteger(); 

stream.collect(groupingBy(x->counter.getAndIncrement()/chunkSize)) 
    .values() 
    .forEach(database::flushChunk); 

Dies keine Leistung oder Speicherauslastung Punkte über Ihre ursprüngliche Lösung gewinnen, weil es immer noch den gesamten Strom materialisieren wird, bevor Sie etwas.

Wenn Sie die Liste nicht materialisieren möchten, hilft Ihnen die Stream-API nicht.

Spliterator<Integer> split = stream.spliterator(); 
int chunkSize = 1000; 

while(true) { 
    List<Integer> chunk = new ArrayList<>(size); 
    for (int i = 0; i < chunkSize && split.tryAdvance(chunk::add); i++){}; 
    if (chunk.isEmpty()) break; 
    database.flushChunk(chunk); 
} 
4

Mit Bibliothek StreamEx Lösung wie

Stream<Integer> stream = IntStream.iterate(0, i -> i + 1).boxed().limit(15); 
AtomicInteger counter = new AtomicInteger(0); 
int chunkSize = 4; 

StreamEx.of(stream) 
     .groupRuns((prev, next) -> counter.incrementAndGet() % chunkSize != 0) 
     .forEach(chunk -> System.out.println(chunk)); 

Ausgabe aussehen würde:

[0, 1, 2, 3] 
[4, 5, 6, 7] 
[8, 9, 10, 11] 
[12, 13, 14] 

groupRuns akzeptiert Prädikat, dass Sie den Stream des Iterators oder spliterator und etwas tun bekommen müssen entscheidet, ob 2 Elemente in derselben Gruppe sein sollen.

Erzeugt eine Gruppe, sobald sie das erste Element findet, das nicht zu ihr gehört.

+0

Dies funktioniert nicht für einen einzelnen Datensatz. Zum Beispiel würde ein Integer-Stream von einfach [1] fehlschlagen. –

+0

Stream von einzelnen Artikel funktioniert für mich. Welche Art von Fehler siehst du? Können Sie Code schreiben, den Sie ausprobiert haben? –

+0

Der Zähler gibt einen falschen Wert zurück, wenn ein Datensatz vorhanden ist. –

Verwandte Themen