web-dev-qa-db-fra.com

Java 8 Lambda Stream forEach avec plusieurs instructions

Je suis encore en train d'apprendre Lambda, veuillez m'excuser si je fais quelque chose de mal

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));

On dirait que forEach ne peut être exécuté que pour une seule instruction. Il ne renvoie pas le flux ou la fonction mis à jour à traiter ultérieurement. J'aurais peut-être choisi le mauvais tout à fait.

Quelqu'un peut-il me guider comment faire cela efficacement?

Encore une question,

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?

Comment convertir ceci en expression Lambda?

38
Reddy

Oublié de se rapporter au premier extrait de code. Je n'utiliserais pas du tout forEach. Puisque vous collectez les éléments du Stream dans un List, il serait plus logique de mettre fin au traitement de Stream avec collect. Ensuite, vous auriez besoin de peek pour définir l'ID.

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

Pour le deuxième extrait, forEach peut exécuter plusieurs expressions, comme n'importe quelle expression lambda peut:

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

Cependant (si vous regardez votre tentative commentée), vous ne pouvez pas utiliser de filtre dans ce scénario, car vous ne traiterez que certaines des entrées (par exemple, les entrées pour lesquelles entry.getA() == null) si vous le faites.

51
Eran
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());
  }
});
8
user3060544

Dans le premier cas, vous pouvez également utiliser l'opération de flux forEach multiligne peek:

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

Dans le second cas, je suggérerais d'extraire le corps de la boucle dans la méthode séparée et d'utiliser la référence de la méthode pour l'appeler via forEach. Même sans lambdas, votre code serait plus clair car le corps de la boucle est un algorithme indépendant qui traite l'entrée unique. Il pourrait donc être utile ailleurs et pouvoir être testé séparément.

Mise à jour après la modification de la question. si vous avez coché les exceptions, vous avez deux options: soit les remplacer par celles qui ne sont pas cochées, soit ne pas utiliser lambdas/streams dans cet élément de code.

6
Tagir Valeev

Il n'est pas nécessaire de regrouper plusieurs opérations dans un seul flux/lambda. Pensez à les séparer en 2 instructions (en utilisant l’importation statique de toList()):

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

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