Reputation: 53
I would like to stream on a collection of object myClass
in order to grouping it using Collectors.groupingBy()
. But, instead of retrieving a Map<String, List<myClass>>
, I would like to group it on a object myOutput
and retrieve a Map<String, myOutput>
. I tried to create a custom collector :
List<myClass> myList = new ArrayList<myClass>();
myList.add(new myClass("a", 1));
myList.add(new myClass("a", 2));
myList.add(new myClass("b", 3));
myList.add(new myClass("b", 4));
Map<String,myOutput> myMap = myList.stream().collect(Collectors.groupingBy(myClass::getA, Collectors.of(myOutput::new, myOutput::accept, myOutput::combine)));
myClass :
protected String a;
protected int b;
public myClass(String aA, int aB)
{
a = aA;
b = aB;
}
public String getA()
{
return a;
}
public int getB()
{
return b;
}
myOutput :
protected int i;
public myOutput()
{
i = 0;
}
public void accept(myClass aMyClass)
{
i += aMyClass.getB();
}
public myOutput combine(myOutput aMyOutput)
{
i += aMyOutput.getI();
return this;
}
public int getI()
{
return i;
}
But with this code, there is a problem with the collector :
Collectors.of(myOutput::new, myOutput::accept, myOutput::combine)
I know in this case a reduction will be much easier, but let's assume there are a lot of operation to do in the myOutput object.
What's wrong with this collector?
Upvotes: 5
Views: 3073
Reputation: 137084
Your collector is fine. You just need to have the Collector.of
static factory (and not Collectors.of
).
This compiles fine and has the output you want
Map<String,myOutput> myMap =
myList.stream()
.collect(Collectors.groupingBy(
myClass::getA,
Collector.of(myOutput::new, myOutput::accept, myOutput::combine)
));
Note, however, that you don't need such a collector. You can reuse an existing one. In this case, you want to group by the a
value and for each element grouped to the same a
, you want to sum their b
value. You can use the built-in Collectors.summingInt(mapper)
where the mapper returns the b
value:
Map<String,Integer> myMap =
myList.stream()
.collect(Collectors.groupingBy(
myClass::getA,
Collectors.summingInt(myClass::getB)
));
Upvotes: 6