首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Collectors.groupingBy不接受空键

Collectors.groupingBy不接受空键
EN

Stack Overflow用户
提问于 2014-03-25 03:45:25
回答 6查看 51.8K关注 0票数 66

在Java 8中,这起作用是:

代码语言:javascript
复制
Stream<Class> stream = Stream.of(ArrayList.class);
HashMap<Class, List<Class>> map = (HashMap)stream.collect(Collectors.groupingBy(Class::getSuperclass));

但这并不是:

代码语言:javascript
复制
Stream<Class> stream = Stream.of(List.class);
HashMap<Class, List<Class>> map = (HashMap)stream.collect(Collectors.groupingBy(Class::getSuperclass));

映射允许空键,List.class.getSuperclass()返回空键。但是Collectors.groupingBy在Collectors.java的第907行发布了一个NPE:

代码语言:javascript
复制
K key = Objects.requireNonNull(classifier.apply(t), "element cannot be mapped to a null key"); 

如果我创建自己的收集器,并将这一行更改为:

代码语言:javascript
复制
K key = classifier.apply(t);  

我的问题是:

1) Collectors.groupingBy的Javadoc没有说它不应该映射空键。这种行为是否出于某种原因而有必要?

2)还有另一种更简单的方法来接受空键,而不必创建自己的收集器吗?

EN

回答 6

Stack Overflow用户

回答已采纳

发布于 2014-03-26 02:14:03

对于第一个问题,我同意skiwi的观点,它不应该抛出一个NPE。我希望他们会改变这一点(或者至少把它添加到javadoc中)。同时,为了回答第二个问题,我决定使用Collectors.toMap而不是Collectors.groupingBy

代码语言:javascript
复制
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;
        }));

或者,封装它:

代码语言:javascript
复制
/** 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;
            });
    }

像这样使用它:

代码语言:javascript
复制
Stream<Class<?>> stream = Stream.of(ArrayList.class);
Map<Class<?>, List<Class<?>>> map = stream.collect(groupingBy_WithNullKeys(Class::getSuperclass));

请注意,rolfl给出了另一个更复杂的答案,它允许您指定您自己的地图和列表供应商。我还没试过呢。

票数 17
EN

Stack Overflow用户

发布于 2015-08-25 15:08:37

在groupingBy之前使用过滤器

过滤掉groupingBy之前的空实例。

下面是一个例子

代码语言:javascript
复制
MyObjectlist.stream()
  .filter(p -> p.getSomeInstance() != null)
  .collect(Collectors.groupingBy(MyObject::getSomeInstance));
票数 8
EN

Stack Overflow用户

发布于 2014-03-25 04:16:43

关于你的第一个问题,从医生那里:

对于返回的Map或List对象的类型、可更改性、可序列化性或线程安全性没有任何保证。

因为并不是所有Map实现都允许空键,所以它们可能添加了空键,从而将映射简化为最常见的允许定义,以便在选择类型时获得最大的灵活性。

关于你的第二个问题,你只需要一个供应商,兰达不管用吗?我还在熟悉Java 8,也许一个更聪明的人可以提供一个更好的答案。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/22625065

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档