web-dev-qa-db-fra.com

Pourquoi devrais-je utiliser des "opérations fonctionnelles" au lieu d'une boucle for?

for (Canvas canvas : list) {
}

NetBeans me propose d'utiliser des "opérations fonctionnelles":

list.stream().forEach((canvas) -> {
});

Mais pourquoi est-ce préféré? Au contraire, il est plus difficile à lire et à comprendre. Vous appelez stream(), puis forEach() à l'aide d'une expression lambda avec le paramètre canvas. Je ne vois pas comment est-ce plus agréable que la boucle for dans le premier extrait.

Évidemment, je parle uniquement d'esthétique. Il y a peut-être un avantage technique qui me manque. Qu'Est-ce que c'est? Pourquoi devrais-je utiliser la deuxième méthode à la place?

42
Omega

Les flux fournissent une bien meilleure abstraction pour la composition des différentes opérations que vous souhaitez effectuer par-dessus les collections ou les flux de données entrant. Surtout lorsque vous devez mapper des éléments, les filtrer et les convertir.

Votre exemple n'est pas très pratique. Considérez le code suivant du site Oracle .

List<Transaction> groceryTransactions = new Arraylist<>();
for(Transaction t: transactions){
  if(t.getType() == Transaction.GROCERY){
    groceryTransactions.add(t);
  }
}
Collections.sort(groceryTransactions, new Comparator(){
  public int compare(Transaction t1, Transaction t2){
    return t2.getValue().compareTo(t1.getValue());
  }
});
List<Integer> transactionIds = new ArrayList<>();
for(Transaction t: groceryTransactions){
  transactionsIds.add(t.getId());
}

peut être écrit en utilisant des flux:

List<Integer> transactionsIds = 
    transactions.stream()
                .filter(t -> t.getType() == Transaction.GROCERY)
                .sorted(comparing(Transaction::getValue).reversed())
                .map(Transaction::getId)
                .collect(toList());

La deuxième option est beaucoup plus lisible. Ainsi, lorsque vous avez des boucles imbriquées ou diverses boucles effectuant un traitement partiel, c'est un très bon candidat pour l'utilisation de l'API Streams/Lambda.

46
luboskrnac

Un autre avantage de l'utilisation de l'API de streaming fonctionnel est qu'elle masque les détails de mise en œuvre. Il décrit uniquement ce qui doit être fait, pas comment. Cet avantage devient évident quand on regarde le changement qui doit être fait, pour passer de l'exécution de code à thread unique à l'exécution de code parallèle. Changez simplement la .stream() en .parallelStream().

16
Stefan Dollase

Au contraire, il est plus difficile à lire et à comprendre.

C'est très subjectif. Je trouve la deuxième version beaucoup plus facile à lire et à comprendre. Il correspond à la façon dont les autres langages (par exemple Ruby, Smalltalk, Clojure, Io, Ioke, Seph) le font, il nécessite moins de concepts à comprendre (c'est juste un appel de méthode normal comme les autres, tandis que le premier exemple est une syntaxe spécialisée).

Si quoi que ce soit, c'est une question de familiarité.

13
Jörg W Mittag