J'ai une liste d'objets client (Customer: int id, bool isActive, int billingCount, ...) et je veux la somme et la moyenne de billingCount. Malheureusement, mon code n'a pas fonctionné. Comment dois-je changer le code pour qu'il fonctionne?
La somme et la moyenne devraient ressembler à ceci:
true 1234
false 1234
Error:(146, 17) java: no suitable method found for collect(java.util.stream.Collector<Customer,capture#1 of ?,java.util.Map<java.lang.Object,java.lang.Integer>>) method java.util.stream.Stream.<R>collect(java.util.function.Supplier<R>,java.util.function.BiConsumer<R,? super java.lang.Boolean>,java.util.function.BiConsumer<R,R>) is not applicable (cannot infer type-variable(s) R (actual and formal argument lists differ in length)) method java.util.stream.Stream.<R,A>collect(java.util.stream.Collector<? super java.lang.Boolean,A,R>) is not applicable (inference variable T has incompatible bounds lower bounds: java.lang.Object,Customer lower bounds: java.lang.Boolean)
J'obtiens l'erreur suivante:
Map<Boolean, Integer> sum = customer.stream() .map(c -> c.getIsActive()) .collect(Collectors.groupingBy(c -> c, Collectors.summingInt(Customer::getBillingCount))); Map<Boolean, Integer> average = customer.stream() .map(c -> c.getIsActive()) .collect(Collectors.groupingBy(c -> c, Collectors.averagingInt(Customer::getBillingCount))); }
3 Réponses :
Avec vos appels map
, vous convertissez votre Stream
en Stream
, ou en un flux de vrais vrais et des faux sur vos clients actifs et inactifs. Vous ne pouvez pas appeler le getBillingCount
du client sur des booléens.
Vous pouvez utiliser le partitioningBy
Collector pour regrouper par un valeur booléenne sans l'appel de map
préalable. Le collecteur en aval peut être le summaryInt
Collector pour collecter la somme et la moyenne (plus quelques autres dont vous n'avez peut-être pas besoin: count, max, min) en même temps.
Map<Boolean, Integer> stats = customer.stream() .collect(Collectors.partitioningBy(Customer::getIsActive, Collectors.summarizingInt(Customer::getBillingCount)));
Cela devrait vous donner les statistiques pour true
et false
dans une seule instruction.
Avez-vous vraiment besoin d'une carte pour les actifs et les inactifs? Qu'en est-il simplement de ceci:
IntSummaryStatistics summaryActive = customer.stream() .filter(Customer::getIsActive) .mapToInt(Customer::getBillingCount) .summaryStatistics(); long sumActive = summary.getSum(); double averageActive = summary.getAverage();
Et vous pouvez faire de même avec inactive en remplaçant le filtre par .filter (c ->! C.getIsActive ())
Vous n'avez pas besoin d'utiliser la carte
. Voir l'exemple ci-dessous:
{false=23, true=8} {false=11.5, true=4.0}
Le code ci-dessus imprime:
List<Customer> customers = Arrays.asList( new Customer(10, true, 5), new Customer(11, true, 3), new Customer(20, false, 12), new Customer(21, false, 11)); Map<Boolean, Integer> sum = customers .stream() .collect(Collectors.groupingBy(Customer::isActive, Collectors.summingInt(Customer::getBillingCount))); System.out.println(sum); Map<Boolean, Double> avg = customers .stream() .collect(Collectors.groupingBy(Customer::isActive, Collectors.averagingInt(Customer::getBillingCount))); System.out.println(avg);