Des collectionneurs.groupingBy n'accepte pas les clés null
Dans Java 8, cela fonctionne:
Stream<Class> stream = Stream.of(ArrayList.class);
HashMap<Class, List<Class>> map = (HashMap)stream.collect(Collectors.groupingBy(Class::getSuperclass));
Mais ce n'est pas le cas:
Stream<Class> stream = Stream.of(List.class);
HashMap<Class, List<Class>> map = (HashMap)stream.collect(Collectors.groupingBy(Class::getSuperclass));
Maps permet une clé null, et de la Liste.classe.getSuperclass() renvoie la valeur null. Mais Les Collectionneurs.groupingBy émet un NPE, à Collectors.java ligne 907:
K key = Objects.requireNonNull(classifier.apply(t), "element cannot be mapped to a null key");
Il fonctionne si je créer mon propre collector, avec cette ligne changé:
K key = classifier.apply(t);
Mes questions sont:
1) La Javadoc de Collectionneurs.groupingBy ne veut pas dire qu'il ne devrait pas carte une clé null. Est-ce le comportement nécessaire pour une raison quelconque?
2) Est-il une autre, la plus facile, à accepter une clé null, sans avoir à créer mon propre collector?
- connexes: stackoverflow.com/questions/24630963/...
Vous devez vous connecter pour publier un commentaire.
J'ai eu le même genre de problème.
Cela a échoué, parce que groupingBy effectue des Objets.requireNonNull sur la valeur retournée par le classificateur:
À l'aide Facultative, cela fonctionne:
Pour la première question, je suis d'accord avec skiwi qu'il ne devrait pas être jeter un
NPE
. J'espère qu'ils vont changer ça (ou au moins l'ajouter à la javadoc). En attendant, pour répondre à la deuxième question, j'ai décidé d'utiliserCollectors.toMap
au lieu deCollectors.groupingBy
:Ou, encapsulation:
Et de l'utiliser comme ceci:
Veuillez noter rolfl a donné un autre, de plus en plus compliqué de répondre, ce qui vous permet d'avoir votre propre Carte et de la Liste des fournisseurs. Je n'ai pas testé.
public static <T,R> Map<R,Long> countGroupBy(Collection<T> list, Function<T,R> groupBy){ Collector<T, ?, Map<R, Long>> mapCollectors = Collectors.toMap( groupBy, l->1L, Long::sum); return list.stream().collect(mapCollectors); }
Utiliser le filtre avant de groupingBy
Filtrer les nuls cas avant groupingBy.
Voici un exemple
result.put(null, myList.stream.filter(p -> p.get() == null).collect(Collectors.toList());
Genre de laid, mais peut-être encore plus pratique que la création d'un collecteur.À votre 1ère question, à partir de la documentation:
Parce que pas tous les Carte implémentations permettent clés null ils ont probablement ajoutée à réduire le plus commun admissible définition d'un plan pour obtenir un maximum de flexibilité lors du choix d'un type.
À votre 2ème question, vous avez juste besoin d'un fournisseur, ne serait pas un lambda de travail? Je suis encore à se familiariser avec Java 8, peut-être une personne plus intelligente pouvez ajouter une meilleure réponse.
Tout d'abord, vous utilisez beaucoup d'objets bruts. Ce n'est pas une bonne idée à tous les, d'abord convertir le suivant:
Class
àClass<?>
, c'est à dire. au lieu d'une crue de type, un paramétrées type avec un inconnu de la classe.HashMap
, vous devez fournir unHashMap
pour le collecteur.D'abord l'correctement tapé le code, sans se soucier un NPE encore:
Maintenant, nous nous débarrassons de la force, jeté là, et au lieu de le faire correctement:
Ici, on remplace la
groupingBy
qui prend juste un classificateur, pour celui qui prend un classificateur, un fournisseur et un collectionneur. C'est le même que ce qu'il y avait avant, mais maintenant il est correctement saisi.Vous êtes tout à fait exact que dans la javadoc, il n'est pas dit qu'il va lancer une
NPE
, et je ne pense pas qu'il devrait être jeter un, comme je suis autorisé à fournir quelle que soit la carte que je veux, et si ma carte permetnull
clés, alors il devrait être permis.Je ne vois pas d'autre moyen de faire plus simple pour l'instant, je vais essayer de regarder plus en elle.
HashMap
, et le plus simplegroupingBy
n'est pas garanti pour revenir. Mon exemple doit avoir été juste la Carte, comme ceci:Stream<Class<?>> stream = Stream.of(ArrayList.class);
Map<Class<?>, List<Class<?>>> map = stream.collect(Collectors.groupingBy(Class::getSuperclass));
Cyclic inference
erreur surClass::getSuperclass
. Si vous supprimez tous les<?>
cette erreur n'est pas affiché. Mais maintenant, j'ai réalisé qu'il compile et fonctionne même avec cette "erreur", de sorte qu'il semble ne pas être une vraie erreur, mais une IntellijIDEA bug.groupingBy
méthodes deCollectors
fin de l'aide de l'intérieur, la même mise en œuvre que rejette les clés null. Ne peux pas croire que personne n'a pris la peine de vérifier avant upvoting...J'ai pensé que je voudrais prendre un moment et essayer de digérer cette question que vous avez. J'ai mis en place un SSCE pour ce que je m'attends si je l'ai fait manuellement, et ce que le
groupingBy
mise en œuvre dans la réalité.Je ne pense pas que c'est une réponse, mais c'est une merveille pourquoi c'est un problème " de la chose. Aussi, si vous voulez, n'hésitez pas à pirater ce code pour avoir un null-friendly collector.
Modifier: générique-friendly de mise en œuvre:
Considérer ce code (le code groupes de valeurs de Chaîne en fonction de la Chaîne.longueur(), (ou null si la Chaîne d'entrée est null)):
Le code ci-dessus génère la sortie: