2016-03-22 5 views
4

Ich möchte auf eine Sammlung von Objekt myClass streamen, um es mit Collectors.groupingBy() zu gruppieren. Aber anstatt eine Map<String, List<myClass>> abzurufen, möchte ich es auf ein Objekt myOutput gruppieren und eine Map<String, myOutput> abrufen. Ich habe versucht, einen benutzerdefinierten Sammler zu erstellen:Java 8 GroupingBy mit Collectors für ein Objekt

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; 
} 

Aber mit diesem Code, gibt es ein Problem mit dem Sammler:

Collectors.of(myOutput::new, myOutput::accept, myOutput::combine) 

Ich weiß in diesem Fall ein Die Reduzierung wird viel einfacher sein, aber nehmen wir an, es gibt eine Menge zu tun in dem myOutput-Objekt.

Was ist los mit diesem Kollektor?

Antwort

6

Ihr Sammler ist in Ordnung. Sie müssen nur die Collector.of statische Fabrik haben (und nicht Collectors.of).

Dies kompiliert fein und hat die Ausgabe möchten Sie

Map<String,myOutput> myMap = 
     myList.stream() 
       .collect(Collectors.groupingBy(
       myClass::getA, 
       Collector.of(myOutput::new, myOutput::accept, myOutput::combine) 
      )); 

Beachten Sie jedoch, dass Sie nicht so ein Sammler brauchen. Sie können ein vorhandenes erneut verwenden. In diesem Fall möchten Sie nach dem Wert a gruppieren und für jedes Element, das zu demselben Element a gruppiert ist, den Wert b summieren. Sie können die eingebaute in Collectors.summingInt(mapper) verwenden, wo der Mapper die b Wert zurückgibt:

Map<String,Integer> myMap = 
    myList.stream() 
      .collect(Collectors.groupingBy(
      myClass::getA, 
      Collectors.summingInt(myClass::getB) 
     )); 
+0

Dank. Ich war ganz nah dran :(Der integrierte summingInt-Kollektor wäre in diesem Fall sicherlich eine bessere Option, aber ich wollte mein Problem mit einem verständlichen Beispiel beschreiben. Meine Bedürfnisse erforderten komplexere myClass- und myOutput-Objekte. –