2015-01-16 9 views
11

Zum Beispiel ist, wenn ich einige Elemente partitionieren möchten, ich so etwas tun konnte:Was den Zweck der partitioningBy

Stream.of("I", "Love", "Stack Overflow") 
     .collect(Collectors.partitioningBy(s -> s.length() > 3)) 
     .forEach((k, v) -> System.out.println(k + " => " + v)); 

die Ausgänge:

false => [I] 
true => [Love, Stack Overflow] 

Aber für mich partioningBy ist nur ein Unterfall von groupingBy. Obwohl Ersterer einen Predicate als Parameter akzeptiert, während der Letztere ein Function ist, sehe ich nur eine Partition als eine normale Gruppierungsfunktion.

Also der gleiche Code tut genau das Gleiche:

Stream.of("I", "Love", "Stack Overflow") 
     .collect(Collectors.groupingBy(s -> s.length() > 3)) 
     .forEach((k, v) -> System.out.println(k + " => " + v)); 

, die auch in einem Map<Boolean, List<String>> führt.

Also gibt es einen Grund, warum ich partioningBy statt groupingBy verwenden sollte? Danke

Antwort

10

partitioningBy wird immer eine Karte mit zwei Einträgen zurückkehren, ein für wo das Prädikat wahr ist und wo es falsch ist. Es ist möglich, dass beide Einträge leere Listen haben, aber sie werden existieren.

Das ist etwas, das groupingBy nicht tun, da es nur Einträge erstellt, wenn sie benötigt werden. Wenn Sie einen leeren Stream an partitioningBy senden, erhalten Sie immer noch zwei Einträge in der Karte, während groupingBy eine leere Karte zurückgibt.

BEARBEITEN: Wie unten erwähnt, wird dieses Verhalten nicht in den Java-Dokumenten erwähnt, aber das Ändern würde den Mehrwert wegnehmen, den partitioningBy derzeit bereitstellt. Für Java 9 ist dies bereits in den Spezifikationen.

+2

Dies ist das vernünftigste Verhalten, aber Ich sehe keine Garantie für zwei Einträge in den Javadocs. Ich habe eine Frage dazu unter http://stackoverflow.com/questions/41287517/must-partitioningby-produce-a-map-with-entries-for-true-and-false gestellt. –

+1

@JoshuaTaylor Danke für die Info! Ich aktualisierte die Antwort, um die Informationen aus dem anderen Thread aufzunehmen. – Oron

13

partitioningBy ist etwas effizienter, mit einer speziellen Map Implementierung für den Fall optimiert, wenn der Schlüssel nur ein boolean ist.

(Es könnte auch helfen, zu klären, was Sie meinen,. partitioningBy über effektiv zu erhalten hilft, dass es eine Boolesche Bedingung verwendet, um die Daten zu partitionieren werden ist)

+5

Angesichts der generell starken Präferenz von Java-APIs, keine Convenience-Special-Cased-Methoden einzubeziehen, bin ich ein wenig überrascht, dass dies die ganze Argumentation war, die es brauchte, um es einzuschließen. Ein kleiner Leistungsvorteil und eine geringfügige Klarstellung.Ich sehe Doug Lea darin denken :) –

+1

Abgesehen davon gibt es noch einen kleinen Unterschied: Wenn alle Elemente die Vorhersage erfüllen, enthält das partitioningBy-Ergebnis immer noch eine falsche Schlüsselzuordnung zu einer leeren Liste, während das groupingBy-Ergebnis nicht die falscher Schlüssel – MGhostSoft

+0

Die "etwas effizientere" Implementierung erstellt 6 Objekte bei jedem Aufruf von "get". Nur weil sie sich nicht die Mühe gemacht haben, '' '' mit einem trivialen Implementierungs-Return-Key zu überschreiben? fürwahr: forFalse'. –

0

partitioningBy Methode wird wieder eine Karte, deren Schlüssel ist immer ein boolescher Wert, aber im Falle von groupingBy Verfahren kann der Schlüssel sein, jeder Objekttyp

//groupingBy 
Map<Object, List<Person>> list2 = new HashMap<Object, List<Person>>(); 
list2 = list.stream().collect(Collectors.groupingBy(p->p.getAge()==22)); 
System.out.println("grouping by age -> " + list2); 

//partitioningBy 
Map<Boolean, List<Person>> list3 = new HashMap<Boolean, List<Person>>(); 
list3 = list.stream().collect(Collectors.partitioningBy(p->p.getAge()==22)); 
System.out.println("partitioning by age -> " + list2); 

Wie Sie sehen können, die Schlüssel für die Karte bei partitioningBy Methode ist immer ein boolescher Wert, aber im Fall von groupingBy Verfahren, ist der Schlüssel Objekttyp

Detaillierte Code ist wie folgt:

class Person { 
    String name; 
    int age; 

    Person(String name, int age) { 
     this.name = name; 
     this.age = age; 
    } 

    public String getName() { 
     return name; 
    } 

    public int getAge() { 
     return age; 
    } 

    public String toString() { 
     return this.name; 
    } 
} 

public class CollectorAndCollectPrac { 
    public static void main(String[] args) { 
     Person p1 = new Person("Kosa", 21); 
     Person p2 = new Person("Saosa", 21); 
     Person p3 = new Person("Tiuosa", 22); 
     Person p4 = new Person("Komani", 22); 
     Person p5 = new Person("Kannin", 25); 
     Person p6 = new Person("Kannin", 25); 
     Person p7 = new Person("Tiuosa", 22); 
     ArrayList<Person> list = new ArrayList<>(); 
     list.add(p1); 
     list.add(p2); 
     list.add(p3); 
     list.add(p4); 
     list.add(p5); 
     list.add(p6); 
     list.add(p7); 

     // groupingBy 
     Map<Object, List<Person>> list2 = new HashMap<Object, List<Person>>(); 
     list2 = list.stream().collect(Collectors.groupingBy(p -> p.getAge() == 22)); 
     System.out.println("grouping by age -> " + list2); 

     // partitioningBy 
     Map<Boolean, List<Person>> list3 = new HashMap<Boolean, List<Person>>(); 
     list3 = list.stream().collect(Collectors.partitioningBy(p -> p.getAge() == 22)); 
     System.out.println("partitioning by age -> " + list2); 

    } 
}