问题描述
在 Java 8 中,这是可行的:
In Java 8, this works:
Stream<Class> stream = Stream.of(ArrayList.class);
HashMap<Class, List<Class>> map = (HashMap)stream.collect(Collectors.groupingBy(Class::getSuperclass));
但这不是:
Stream<Class> stream = Stream.of(List.class);
HashMap<Class, List<Class>> map = (HashMap)stream.collect(Collectors.groupingBy(Class::getSuperclass));
Maps 允许使用 null 键,并且 List.class.getSuperclass() 返回 null.但是 Collectors.groupingBy 在 Collectors.java 第 907 行发出 NPE:
Maps allows a null key, and List.class.getSuperclass() returns null. But Collectors.groupingBy emits a NPE, at Collectors.java, line 907:
K key = Objects.requireNonNull(classifier.apply(t), "element cannot be mapped to a null key");
如果我创建自己的收集器,它会起作用,将这一行更改为:
It works if I create my own collector, with this line changed to:
K key = classifier.apply(t);
我的问题是:
1) Collectors.groupingBy 的 Javadoc 并没有说它不应该映射空键.出于某种原因,这种行为是否必要?
1) The Javadoc of Collectors.groupingBy doesn't say it shouldn't map a null key. Is this behavior necessary for some reason?
2) 是否有另一种更简单的方法来接受空键,而不必创建自己的收集器?
2) Is there another, easier way, to accept a null key, without having to create my own collector?
推荐答案
对于第一个问题,我同意skiwi 的观点,它不应该抛出NPE
.我希望他们会改变这一点(或者至少将它添加到 javadoc 中).同时,为了回答第二个问题,我决定使用 Collectors.toMap
而不是 Collectors.groupingBy
:
For the first question, I agree with skiwi that it shouldn't be throwing a NPE
. I hope they will change that (or else at least add it to the javadoc). Meanwhile, to answer the second question I decided to use Collectors.toMap
instead of Collectors.groupingBy
:
Stream<Class<?>> stream = Stream.of(ArrayList.class);
Map<Class<?>, List<Class<?>>> map = stream.collect(
Collectors.toMap(
Class::getSuperclass,
Collections::singletonList,
(List<Class<?>> oldList, List<Class<?>> newEl) -> {
List<Class<?>> newList = new ArrayList<>(oldList.size() + 1);
newList.addAll(oldList);
newList.addAll(newEl);
return newList;
}));
或者,封装它:
/** Like Collectors.groupingBy, but accepts null keys. */
public static <T, A> Collector<T, ?, Map<A, List<T>>>
groupingBy_WithNullKeys(Function<? super T, ? extends A> classifier) {
return Collectors.toMap(
classifier,
Collections::singletonList,
(List<T> oldList, List<T> newEl) -> {
List<T> newList = new ArrayList<>(oldList.size() + 1);
newList.addAll(oldList);
newList.addAll(newEl);
return newList;
});
}
并像这样使用它:
Stream<Class<?>> stream = Stream.of(ArrayList.class);
Map<Class<?>, List<Class<?>>> map = stream.collect(groupingBy_WithNullKeys(Class::getSuperclass));
请注意 rolfl 给出了另一个更复杂的答案,它允许您指定自己的地图和列表供应商.我没有测试过.
Please note rolfl gave another, more complicated answer, which allows you to specify your own Map and List supplier. I haven't tested it.
这篇关于Collectors.groupingBy 不接受空键的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!