2016-06-06 2 views
-1

Gibt es eine Möglichkeit, dieses Stück Code parallelisieren:For-Schleife einschließlich, wenn auf parallelStream() Ausdruck

HashMap<String, Car> cars; 
List<Car> snapshotCars = new ArrayList<>(); 
... 
for (final Car car : cars.values()) { 
    if (car.isTimeInTimeline(curTime)) { 
     car.updateCalculatedPosition(curTime); 
     snapshotCars.add(car); 
    } 
} 

Update: Dies ist, was vor um Hilfe zu fragen Ich habe versucht:

snapshotCars.addAll(cars.values().parallelStream() 
           .filter(c -> c.isTimeInTimeline(curTime)) 
           .collect(Collectors.toList())); 

Wie Könnte ich diese Linie integrieren? -> car.updateCalculatedPosition (curTime);

+0

Haben Sie versucht, in die Stream-API zu konvertieren? Auf welche Probleme hast du gestoßen? – khelwood

+0

Sicher ist. Jetzt sollten Sie es versuchen. Erwarte nicht, dass wir deine Arbeit für dich tun. – GhostCat

+0

@RealSkeptic Ich möchte, dass Sie mir sagen, wie man es schreibt. Kleiner semantischer Unterschied, denke ich. –

Antwort

0

Wenn Sie parallelisierten Zugriff auf eine Liste möchten möchten Sie vielleicht Collections.synchonizedList verwenden, um eine Thread-sichere Liste zu erhalten:

List<Car> snapshotCars = Collections.synchronizedList(new ArrayList<>()); 

Dann können Sie die Stream-API wie so verwenden:

cars.values() 
    .parallelStream() 
    .filter(car -> car.isTimeInTimeline(curTime)) 
    .forEach(car -> { 
     car.updateCalculatedPosition(curTime); 
     snapshotCars.add(car); 
    }); 
1

Nun, unter der Annahme, dass updateCalculatedPosition keinen Einfluss auf den Zustand außerhalb des Car Objekts hat, auf dem es ausgeführt wird, kann es sicher genug sein, dafür peek zu verwenden:

List<Car> snapshotCars = cars.values() 
    .parallelStream() 
    .filter(c -> c.isTimeInTimeline(curTime)) 
    .peek(c -> c.updateCalculatedPosition(curTime)) 
    .collect(Collectors.toCollection(ArrayList::new)); 

Ich sage, das ist "sicher genug", weil die collect diktiert, welche Elemente von peek gespäht werden, und diese werden notwendigerweise alle Elemente sein, die den Filter bestanden haben. Lesen Sie jedoch this answer aus dem Grund, warum peek generell für "signifikante" Operationen vermieden werden sollte.

Ihre Peek-freie Alternative ist zunächst, Filter und sammelt, und aktualisieren Sie dann die fertige Kollektion mit:

List<Car> snapshotCars = cars.values() 
    .parallelStream() 
    .filter(c -> c.isTimeInTimeline(curTime)) 
    .collect(Collectors.toCollection(ArrayList::new)); 
snapShotCars.parallelStream() 
    .forEach(c -> c.updateCalculatedPosition(curTime)); 

Dies ist sicherer von einer API-Sicht, aber weniger parallel - Sie starten die Aktualisierung die Positionen nach dem Sie gefiltert und gesammelt haben.

+0

Wenn das OP nicht explizit sagt, dass eine 'ArrayList' benötigt wird, würde ich einfach' Collectors.toList() 'verwenden. – Holger

0

Neben RealSkeptic’s answer, können Sie alternativ Ihre eigenen Kollektor verwenden:

List<Car> snapshotCars = cars.values().parallelStream() 
    .filter(c -> c.isTimeInTimeline(curTime)) 
    .collect(ArrayList::new, 
      (l,c) -> { c.updateCalculatedPosition(curTime); l.add(c); }, 
      List::addAll); 

Beachten Sie, dass .collect(Collectors.toList()) gleichwertig ist (wenn auch nicht notwendigerweise identisch) zu .collect(Collectors.toCollection(ArrayList::new)), die zu .collect(ArrayList::new, List::add, List::addAll) entspricht.

Also unser Custom Collector macht eine ähnliche Operation, aber ersetzt den Akku mit einer Funktion, die auch die gewünschte zusätzliche Operation durchführt.

Verwandte Themen