Java 8 Lambda Stream forEach mit mehreren Anweisungen

Lesezeit: 5 Minuten

Benutzer-Avatar
RaceBase

Ich bin immer noch dabei, Lambda zu lernen, bitte entschuldigen Sie, wenn ich etwas falsch mache

final Long tempId = 12345L;
List<Entry> updatedEntries = new LinkedList<>();

for (Entry entry : entryList) {
    entry.setTempId(tempId);
    updatedEntries.add(entityManager.update(entry, entry.getId()));
}

//entryList.stream().forEach(entry -> entry.setTempId(tempId));

Sieht aus als ob forEach kann nur für eine Anweisung ausgeführt werden. Es gibt keinen aktualisierten Stream oder keine aktualisierte Funktion zur weiteren Verarbeitung zurück. Vielleicht habe ich die falsche gewählt.

Kann mir jemand helfen, wie ich das effektiv mache?

Noch eine Frage,

public void doSomething() throws Exception {
    for(Entry entry: entryList){
        if(entry.getA() == null){
            printA() throws Exception;
        }
        if(entry.getB() == null){
            printB() throws Exception;
        }
        if(entry.getC() == null){
            printC() throws Exception;
        }
    }
}
    //entryList.stream().filter(entry -> entry.getA() == null).forEach(entry -> printA()); something like this?

Wie konvertiere ich das in einen Lambda-Ausdruck?

Benutzer-Avatar
Eran

Habe vergessen, mich auf das erste Code-Snippet zu beziehen. würde ich nicht verwenden forEach überhaupt. Da Sie die Elemente der sammeln Stream in ein Listwäre es sinnvoller, die zu beenden Stream Verarbeitung mit collect. Dann bräuchte man peek um die ID einzustellen.

List<Entry> updatedEntries = 
    entryList.stream()
             .peek(e -> e.setTempId(tempId))
             .collect (Collectors.toList());

Für den zweiten Ausschnitt forEach kann mehrere Ausdrücke ausführen, genau wie jeder Lambda-Ausdruck:

entryList.forEach(entry -> {
  if(entry.getA() == null){
    printA();
  }
  if(entry.getB() == null){
    printB();
  }
  if(entry.getC() == null){
    printC();
  }
});

Allerdings (mit Blick auf Ihren kommentierten Versuch) können Sie in diesem Szenario keinen Filter verwenden, da Sie nur einige der Einträge verarbeiten (z. B. die Einträge für which entry.getA() == null) wenn Sie tun.

  • ist es nicht peek() wird nur zum Debuggen empfohlen. Ich denke, man sollte stattdessen map() ausprobieren

    – Atom217

    22. September 2017 um 7:46 Uhr

  • leider sollten wir peek nicht verwenden … siehe rules.sonarsource.com/java/RSPEC-3864

    – Cristiano Costantini

    9. Juli 2021 um 3:16 Uhr

List<String> items = new ArrayList<>();
items.add("A");
items.add("B");
items.add("C");
items.add("D");
items.add("E");

//lambda
//Output : A,B,C,D,E
items.forEach(item->System.out.println(item));

//Output : C
items.forEach(item->{
    System.out.println(item);
    System.out.println(item.toLowerCase());
  }
});

  • Das scheint eine ungültige Syntax zu sein. Gibt es nicht extra } Am Ende?

    – Markus

    28. Oktober 2020 um 0:02 Uhr

Im ersten Fall alternativ zu mehrzeilig forEach du kannst den … benutzen peek Stream-Betrieb:

entryList.stream()
         .peek(entry -> entry.setTempId(tempId))
         .forEach(updatedEntries.add(entityManager.update(entry, entry.getId())));

Im zweiten Fall würde ich vorschlagen, den Schleifenkörper in die separate Methode zu extrahieren und die Methodenreferenz zu verwenden, um ihn über aufzurufen forEach. Auch ohne Lambdas würde es Ihren Code klarer machen, da der Schleifenkörper ein unabhängiger Algorithmus ist, der den einzelnen Eintrag verarbeitet, sodass er auch an anderen Stellen nützlich sein kann und separat getestet werden kann.

Aktualisierung nach Bearbeitung der Frage. Wenn Sie Ausnahmen überprüft haben, haben Sie zwei Möglichkeiten: Entweder ändern Sie sie in ungeprüfte oder verwenden überhaupt keine Lambdas/Streams in diesem Codeabschnitt.

  • Was ist der Vorteil der Verwendung peek. Ich habe die Funktion nicht ausprobiert

    – RaceBase

    30. Juni 2015 um 5:59 Uhr

  • @Reddy In diesem Fall sehe ich keinen wirklichen Vorteil, da man das ausführen kann setTempId Rufen Sie entweder an peek oder hinein forEach, und das Verhalten wird ähnlich sein. Wenn Sie jedoch nicht verwenden forEach überhaupt, und verwenden Sie stattdessen collect, um die Ausgabeliste zu erstellen (siehe meine aktualisierte Antwort), die Sie benötigen würden peek um anzurufen setTempId.

    – Eran

    30. Juni 2015 um 6:09 Uhr

  • Denk daran, dass peek sollte hauptsächlich zu Debug-Zwecken verwendet werden. Verwenden forEach beim Anwenden von Nebeneffekten auf Ihre gestreamten Daten.

    – Simon Cedergren Malmqvist

    24. Februar 2017 um 13:46 Uhr

Sie müssen nicht mehrere Operationen in einen Stream/Lambda packen. Erwägen Sie, sie in zwei Anweisungen aufzuteilen (unter Verwendung des statischen Imports von toList()):

entryList.forEach(e->e.setTempId(tempId));

List<Entry> updatedEntries = entryList.stream()
  .map(e->entityManager.update(entry, entry.getId()))
  .collect(toList());

Mein bevorzugter Ansatz ist das Verketten java.util.function.Consumer<?> mit andThen(...).

Auf Ihr Beispiel angewendet, kann es geschrieben werden in:

entryList.stream()
  .forEach(
    ((Consumer<Entry>) entry -> entry.setTempId(tempId))
    .andThen(entry -> updatedEntries.add(entityManager.update(entry, entry.getId())))
  );

So gesehen, ist das nicht so schön zu lesen … aber Sie können die 2 Verbraucher in lokale Funktionsvariablen verschieben und es würde so schön werden wie:

Consumer<Entry> c1 = entry -> entry.setTempId(tempId);
Consumer<Entry> c2 = entry -> updatedEntries.add(entityManager.update(entry, entry.getId()));
entryList.stream().forEach(c1.andThen(c2));

Bonus

Sie können Ihren Kombinator von Verbrauchern wie folgt schreiben:

public static <T> Consumer<T> combine(Consumer<? super T>... consumers){
  return (T t) ->   Arrays.stream(consumers).forEach(c -> c.accept
}

und es wird erlauben, das obige Beispiel neu zu schreiben in:

entryList.stream()
  .forEach(combine(
    entry -> entry.setTempId(tempId),
    entry -> updatedEntries.add(entityManager.update(entry, entry.getId()))));

Ich wünsche Consumer Klasse hatte eine Methode, um mehrere Verbraucher des gleichen Typs zu kombinieren, vielleicht diese combine existiert schon irgendwo und ich weiß es nicht, also lade ich dich ein zu suchen 😅

1054510cookie-checkJava 8 Lambda Stream forEach mit mehreren Anweisungen

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy