2015-01-16 21 views
11

Per esempio, se ho intenzione di dividere alcuni elementi, avrei potuto fare qualcosa di simile:Qual è lo scopo di partitioningBy

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

quali uscite:

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

Ma per me partioningBy è solo una subcase di groupingBy. Anche se il primo accetta un parametro Predicate mentre il secondo è un Function, vedo solo una partizione come una normale funzione di raggruppamento.

Così lo stesso codice fa esattamente la stessa cosa:

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

che si traduce anche in un Map<Boolean, List<String>>.

Quindi c'è qualche ragione per cui dovrei usare partioningBy invece di groupingBy? Grazie

risposta

10

partitioningBy restituirà sempre una mappa con due voci, una per dove il predicato è vero e uno per dove è falso. È possibile che entrambe le voci abbiano elenchi vuoti, ma esisteranno.

Questo è qualcosa che lo groupingBy non farà, poiché crea solo voci quando sono necessarie.

In caso estremo, se si invia un flusso vuoto a partitioningBy, nella mappa verranno comunque visualizzate due voci mentre groupingBy restituirà una mappa vuota.

MODIFICA: come accennato in precedenza, questo comportamento non è menzionato nei documenti Java, tuttavia la modifica potrebbe togliere il valore aggiunto partitioningBy attualmente fornito. Per Java 9 questo è già nelle specifiche.

+2

Questo è il comportamento più ragionevole, ma Non vedo la garanzia per due voci in javadocs. Ho fatto una domanda al riguardo su http://stackoverflow.com/questions/41287517/must-partitioningby-produce-a-map-with-entries-for-true-and-false. –

+1

@JoshuaTaylor Grazie per le informazioni! Ho aggiornato la risposta per includere le informazioni dall'altro thread. – Oron

13

partitioningBy è leggermente più efficiente, utilizzando un'implementazione speciale Map ottimizzata per quando la chiave è solo una boolean.

(Potrebbe anche aiutare a chiarire cosa si intende;. partitioningBy aiuta ad ottenere in modo efficace attraverso che c'è una condizione booleana utilizzata per partizionare i dati)

+5

Considerando la preferenza generalmente forte delle API Java per non includere i metodi di convenienza con involucro speciale, sono un po 'sorpreso dal fatto che questo sia l'argomento per includerlo. Un margine di prestazione minore e un chiarimento minore.Vedo che ci pensa Doug Lea :) –

+1

Oltre a ciò, c'è un'altra piccola differenza: se tutti gli elementi soddisfano il Predict, il risultato partitioningBy contiene ancora un falso key mapping a un elenco vuoto, mentre il groupingBy non avrà il risultato chiave falsa. – MGhostSoft

+0

L'implementazione "leggermente più efficiente" crea 6 oggetti per ogni chiamata di get. Solo perché non si sono preoccupati di sovrascrivere 'get' con un'immediata chiave di ritorno dell'implementazione'? forTrue: forFalse'. –

0

metodo partitioningBy restituirà una mappa la cui chiave è sempre un valore booleano, ma in caso di groupingBy metodo, la chiave può essere di qualsiasi tipo di oggetto

//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); 

Come si può vedere, la chiave per la mappa in caso di metodo partitioningBy è sempre un valore booleano, ma in caso di metodo groupingBy, la chiave è di tipo Object

codice dettagliato è il seguente:

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

    } 
}