I have a list of Transactions whom I wanted to :
My Code snippets looks like :
Map<Integer, Map<String, Result> res = transactions.stream().collect(Collectors
.groupingBy(Transaction::getYear,
groupingBy(Transaction::getType),
reducing((a,b)-> new Result("YEAR_TYPE", a.getAmount() + b.getAmount()))
));
Transaction Class :
class Transaction {
private int year;
private String type;
private int value;
}
Result Class :
class Result {
private String group;
private int amount;
}
it seems to be not working, what should I do to fix this making sure it works on parallel streams too?
In the context, Collectors.reducing
would help you reduce two Transaction
objects into a final object of the same type. In your existing code what you could have done to map to Result
type was to use Collectors.mapping
and then trying to reduce it.
But reducing without an identity provides and Optional
wrapped value for a possible absence. Hence your code would have looked like ;
Map<Integer, Map<String, Optional<Result>>> res = transactions.stream()
.collect(Collectors.groupingBy(Transaction::getYear,
Collectors.groupingBy(Transaction::getType,
Collectors.mapping(t -> new Result("YEAR_TYPE", t.getValue()),
Collectors.reducing((a, b) ->
new Result(a.getGroup(), a.getAmount() + b.getAmount()))))));
to thanks to Holger, one can simplify this further
…and instead of
Collectors.mapping(func, Collectors.reducing(op))
you can useCollectors.reducing(id, func, op)
Instead of using this and a combination of Collectors.grouping
and Collectors.reducing
, transform the logic to use Collectors.toMap
as:
Map<Integer, Map<String, Result>> result = transactions.stream()
.collect(Collectors.groupingBy(Transaction::getYear,
Collectors.toMap(Transaction::getType,
t -> new Result("YEAR_TYPE", t.getValue()),
(a, b) -> new Result(a.getGroup(), a.getAmount() + b.getAmount()))));
The answer would stand complete with a follow-up read over Java Streams: Replacing groupingBy and reducing by toMap.