Par exemple, si j'ai l'intention de partitionner certains éléments, je pourrais faire quelque chose comme:
Stream.of("I", "Love", "Stack Overflow")
.collect(Collectors.partitioningBy(s -> s.length() > 3))
.forEach((k, v) -> System.out.println(k + " => " + v));
qui produit:
false => [I]
true => [Love, Stack Overflow]
Mais pour moi, partioningBy
n'est qu'un sous-cas de groupingBy
. Bien que le premier accepte une Predicate
en tant que paramètre, tandis que le dernier un Function
, je ne vois qu'une partition comme une fonction de regroupement normale.
Donc, le même code fait exactement la même chose:
Stream.of("I", "Love", "Stack Overflow")
.collect(Collectors.groupingBy(s -> s.length() > 3))
.forEach((k, v) -> System.out.println(k + " => " + v));
ce qui entraîne également un Map<Boolean, List<String>>
.
Y a-t-il une raison pour laquelle je devrais utiliser partioningBy
au lieu de groupingBy
? Merci
partitioningBy
retournera toujours une carte avec deux entrées, une pour où le prédicat est vrai et l'autre pour où il est faux. Il est possible que les deux entrées aient des listes vides, mais qu'elles existent.
C'est une chose que groupingBy
ne fera pas, car cela ne crée des entrées que lorsqu'elles sont nécessaires.
Dans les cas extrêmes, si vous envoyez un flux vide à partitioningBy
, vous aurez toujours deux entrées dans la carte, alors que groupingBy
renverra une carte vide.
EDIT: Comme indiqué ci-dessous, ce comportement n’est pas mentionné dans la documentation Java, mais sa modification aurait pour effet de supprimer la valeur ajoutée que partitioningBy
fournit actuellement. Pour Java 9, cela figure déjà dans les spécifications.
partitioningBy
est légèrement plus efficace, en utilisant une implémentation Map
spéciale optimisée pour une clé boolean
.
(Cela pourrait également aider à clarifier ce que vous voulez dire; partitioningBy
aide à bien comprendre qu'il existe une condition booléenne utilisée pour partitionner les données.)
Une autre différence entre groupingBy
et partitioningBy
est que le premier prend un Function<? super T, ? extends K>
et le dernier un Predicate<? super T>
.
Lorsque vous transmettez une référence de méthode ou une expression lambda, telle que s -> s.length() > 3
, elles peuvent être utilisées par l'une de ces deux méthodes (le compilateur déduira le type d'interface fonctionnelle en fonction du type requis par la méthode choisie).
Toutefois, si vous avez une instance Predicate<T>
, vous ne pouvez la transmettre qu'à Collectors.partitioningBy()
. Il ne sera pas accepté par Collectors.groupingBy()
.
De même, si vous avez une instance Function<T,Boolean>
, vous ne pouvez la transmettre qu’à Collectors.groupingBy()
. Il ne sera pas accepté par Collectors.partitioningBy()
.
La méthode partitioningBy retournera une mappe dont la clé est toujours une valeur booléenne, mais dans le cas de la méthode groupingBy , la clé peut être de tout type Object.
//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);
Comme vous pouvez le constater, la clé de mappage dans le cas de la méthode partitioningBy est toujours une valeur booléenne, mais dans le cas de la méthode groupingBy, la clé est Type d'objet
Le code détaillé est le suivant:
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);
}
}