Ik ben nog bezig met het leren van Lambda, excuseer me als ik iets verkeerd doe
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));
Het lijkt erop dat forEach
slechts voor één instructie kan worden uitgevoerd. Het retourneert geen bijgewerkte stream of functie om verder te verwerken. Ik heb misschien helemaal de verkeerde gekozen.
Kan iemand me helpen hoe ik dit effectief kan doen?
Nog een vraag,
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?
Hoe converteer ik dit naar Lambda-expressie?
Antwoord 1, autoriteit 100%
Vergeten te verwijzen naar het eerste codefragment. Ik zou forEach
helemaal niet gebruiken. Aangezien u de elementen van de Stream
verzamelt in een List
, zou het logischer zijn om de Stream
-verwerking te beëindigen met collect
. Dan heb je peek
nodig om de ID in te stellen.
List<Entry> updatedEntries =
entryList.stream()
.peek(e -> e.setTempId(tempId))
.collect (Collectors.toList());
Voor het tweede fragment kan forEach
meerdere expressies uitvoeren, net zoals elke lambda-expressie kan:
entryList.forEach(entry -> {
if(entry.getA() == null){
printA();
}
if(entry.getB() == null){
printB();
}
if(entry.getC() == null){
printC();
}
});
U kunt echter (gezien uw poging met commentaar) geen filter gebruiken in dit scenario, omdat u slechts enkele van de vermeldingen verwerkt (bijvoorbeeld de vermeldingen waarvoor entry.getA() == null
) als je dat doet.
Antwoord 2, autoriteit 27%
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());
}
});
Antwoord 3, autoriteit 8%
In het eerste geval kunt u als alternatief voor forEach
met meerdere regels de streambewerking peek
gebruiken:
entryList.stream()
.peek(entry -> entry.setTempId(tempId))
.forEach(updatedEntries.add(entityManager.update(entry, entry.getId())));
In het tweede geval raad ik aan om de hoofdtekst van de lus naar de afzonderlijke methode te extraheren en de methodereferentie te gebruiken om deze aan te roepen via forEach
. Zelfs zonder lambda’s zou het je code duidelijker maken, omdat de lusbody een onafhankelijk algoritme is dat de enkele invoer verwerkt, dus het kan ook op andere plaatsen nuttig zijn en afzonderlijk worden getest.
Update na bewerken van vragen. als je uitzonderingen hebt aangevinkt, heb je twee opties: verander ze in niet-aangevinkte of gebruik helemaal geen lambdas/streams bij dit stukje code.
Antwoord 4, autoriteit 8%
Je hoeft niet meerdere bewerkingen in één stream/lambda te proppen. Overweeg ze te scheiden in 2 instructies (met behulp van statische import van toList()
):
entryList.forEach(e->e.setTempId(tempId));
List<Entry> updatedEntries = entryList.stream()
.map(e->entityManager.update(entry, entry.getId()))
.collect(toList());
Antwoord 5
Mijn voorkeur gaat uit naar het samenvoegen van java.util.function.Consumer<?>
met andThen(...)
.
Toegepast op uw voorbeeld, kan het worden geschreven in:
entryList.stream()
.forEach(
((Consumer<Entry>) entry -> entry.setTempId(tempId))
.andThen(entry -> updatedEntries.add(entityManager.update(entry, entry.getId())))
);
op deze manier gezien, is niet zo leuk om te lezen… maar je kunt de 2 consumenten verplaatsen naar lokale functievariabelen en het zou zo mooi worden als:
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
U kunt uw combinator van consumenten schrijven als:
public static <T> Consumer<T> combine(Consumer<? super T>... consumers){
return (T t) -> Arrays.stream(consumers).forEach(c -> c.accept(t));
}
en het zal het mogelijk maken om het bovenstaande voorbeeld te herschrijven in:
entryList.stream()
.forEach(combine(
entry -> entry.setTempId(tempId),
entry -> updatedEntries.add(entityManager.update(entry, entry.getId()))));
Ik wou dat de klasse Consumer
een methode had om meerdere consumenten van hetzelfde type te combineren, misschien bestaat deze combine
al ergens en ben ik me er niet van bewust, dus ik nodigen u uit om te zoeken 😅