42 votes

Meilleure façon d'enchaîner les réductions avec Java 8

J'ai le code suivant que j'essaie d'améliorer :

BigDecimal total = entity.getAssociate().stream().map(Associates::getPropertyA)
    .reduce(BigDecimal.ZERO, BigDecimal::add);
total = entity.getAssociate().stream().map(Associates::getPropertyB)
    .reduce(total, BigDecimal::add);
total = entity.getAssociate().stream().map(Associates::getPropertyC)
    .reduce(total, BigDecimal::add);
total = entity.getAssociate().stream().map(Associates::getPropertyD)
    .reduce(total, BigDecimal::add);

Cela fonctionne, mais j'ai vraiment l'impression qu'il y a une meilleure façon de faire. Quelqu'un peut-il m'éclairer à ce sujet ?

59voto

Eran Points 35360

Si toutes ces propriétés sont du même type (il semble qu'elles soient toutes BigDecimal ), vous pouvez utiliser flatMap pour créer un seul Stream d'eux tous et ensuite reduce à la somme totale :

BigDecimal total = 
    entity.getAssociate()
          .stream()
          .flatMap (a -> Stream.of(a.getPropertyA(),a.getPropertyB(),a.getPropertyC(),a.getPropertyD()))
          .reduce(BigDecimal.ZERO, BigDecimal::add);

32voto

Manos Nikolaidis Points 7375

Vous pouvez simplement ajouter en chaîne toutes les propriétés à l'intérieur de map :

BigDecimal total = entity.getAssociate().stream()
            .map(a -> a.getPropertyA()
                    .add(a.getPropertyB())
                    .add(a.getPropertyC())
                    .add(a.getPropertyD()))
            .reduce(BigDecimal.ZERO, BigDecimal::add);

Notez que cela change l'ordre dans lequel les chiffres sont ajoutés.

23voto

Si vous pouviez ajouter la méthode suivante à l Associates classe :

public BigDecimal getSubtotal() {
    return propertyA.add(propertyB).add(propertyC).add(propertyD);
}

Ensuite, l'exécution de la tâche serait facile :

BigDecimal total = entity.getAssociate().stream()
    .map(Associate::getSubtotal)
    .reduce(BigDecimal::add)
    .orElse(BigDecimal.ZERO);

16voto

Marco13 Points 14743

Les mots "meilleur" ou "meilleure" devraient faire référence à une mesure. La performance ? Lisibilité ? Elégance ?

El réponse d'Eran montre une approche, à savoir la création de petits flux contenant les valeurs de propriété A, B, C et D pour chaque associé, et la mise à plat de ces valeurs dans un flux plus important. L'ordre d'addition dans cette approche est

A0 + B0 + C0 + D0  +  A1 + B1 + C1 + D1  + ... +  An + Bn + Cn + Dn

Une autre option serait de créer des flux individuels des propriétés A, B, C et D, et de concaténer ces flux avant d'appliquer la réduction. Cela pourrait être fait avec des Stream#concat mais de manière plus élégante et plus souple en utilisant les appels flatMap avec une fonction d'identité :

Stream<BigDecimal> stream = Stream.of(
    entity.getAssociate().stream().map(Associates::getPropertyA),
    entity.getAssociate().stream().map(Associates::getPropertyB),
    entity.getAssociate().stream().map(Associates::getPropertyA),
    entity.getAssociate().stream().map(Associates::getPropertyC))
    .flatMap(Function.identity());

BigDecimal total = stream.reduce(BigDecimal.ZERO, BigDecimal::add);

Le point clé est que dans ce cas, l'ordre de sommation est

A0 + A1 + ... + An + B0 + B1 + ... + Bn + C0 + C1 + ... + Cn 

(Techniquement, cela ne fait peut-être pas une grande différence. Mais c'est une approche qui est conceptuellement différent de ceux qui ont été proposés jusqu'à présent (en termes d'ordre de sommation), et peut donc être mentionné comme une option - en outre, il est plus similaire à l'approche que vous utilisez actuellement, mais sans la valeur d'identité brisée pour la réduction)

6voto

Eugene Points 6271

Ou simplement un forEach :

BigDecimal[] total = new BigDecimal[] { BigDecimal.ZERO };
entity.getAssociate().stream().forEach(a -> {
    total[0] = total[0].add(a.getPropertyA());
    // ... and so on for all others
});

Par ailleurs, votre implémentation actuelle est erronée puisque vous violez le principe de l'égalité des chances. identity de la réduction.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X