Java 8 Stream - 使用Custom Collector时出现NullPointerException

Kay*_*ayV 2 java-8 java-stream collectors

我通过实现Collector接口并覆盖其方法来实现自定义收集器.Collector实现如下:

class MyCustomCollector implements Collector<Person, StringJoiner, String>{

    @Override
    public Supplier<StringJoiner> supplier() {
        // TODO Auto-generated method stub
        return () -> new StringJoiner("|");
    }

    @Override
    public BiConsumer<StringJoiner, Person> accumulator() {
        // TODO Auto-generated method stub
        return (joiner,person) -> joiner.add(person.name.toUpperCase());
    }

    @Override
    public BinaryOperator<StringJoiner> combiner() {
        // TODO Auto-generated method stub
        return (joiner1, joiner2) -> joiner1.merge(joiner2);
    }

    @Override
    public Function<StringJoiner, String> finisher() {
        // TODO Auto-generated method stub
        return StringJoiner::toString;
    }

    @Override
    public Set<java.util.stream.Collector.Characteristics> characteristics() {
        // TODO Auto-generated method stub
        return null;
    }
}
Run Code Online (Sandbox Code Playgroud)

这是我的Person类:

class Person implements Comparable<Object>{
    String name;
    int age;

    Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString() {
        return name;
    }

    public int compareTo(Object obj){
        int returnValue;
        if(age ==((Person) obj).age)
            returnValue=0;
        else
            if(age >((Person) obj).age)
                returnValue = 1;
            else
                returnValue =-1;

        return returnValue;
    }

    public boolean equals(Object obj)
    {
        if(!(obj instanceof Person))
            return false;

        return (age == ((Person) obj).age); 
    }

    public int hashCode()
    {  
        return name.hashCode();  
    } 

}
Run Code Online (Sandbox Code Playgroud)

这是我的呼吁声明......

List<Person> persons =
        Arrays.asList(
            new Person("Max", 18),
            new Person("Peter", 23),
            new Person("Pamela", 23),
            new Person("David", 12),
            new Person("Pam", 23));
String names2 = persons.stream()
            .collect(new MyCustomCollector());
Run Code Online (Sandbox Code Playgroud)

执行上面的语句时,我得到一个NullPointerException,如下所示:

java.util中java.util.stream.ReduceOps $ 3.getOpFlags(ReduceOps.java:185)中java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)中的线程"main"java.lang.NullPointerException中的异常.stream.ReferencePipeline.collect(ReferencePipeline.java:499)at com.my.j8.TestStreams.main(TestStreams.java:231)

任何人都可以告诉我在哪里弄错了吗?

Gho*_*ica 8

这里:

public Set<java.util.stream.Collector.Characteristics> characteristics() {
    return null;
Run Code Online (Sandbox Code Playgroud)

返回一个集而不是null; 喜欢

private final static Set<Characteristics> EMPTY = Collections.emptySet();
Run Code Online (Sandbox Code Playgroud)

...

return EMPTY;
Run Code Online (Sandbox Code Playgroud)

要不就

return Collections.emptySet();
Run Code Online (Sandbox Code Playgroud)

(因为Collections类已经自己拥有一些EMPTY常量).

核心要点是:该接口包含该方法; 并且"我没有使用这部分"仍然要求你"合理地"实现该方法.因此,请记住未来:任何收集返回的界面都允许通过返回空的东西来说"无内容" ; 而不是一个空的东西!

当然,最终问题可能是周围的框架没有检查该方法是否返回null.但正如所说:当你处理任何类型的集合时,忘记使用null.如果没有,请创建该类型的空集合对象!

避免NPE的一个关键步骤是首先不返回 null.

及以后:随着尤金指出-你可能想真的很用心,如果你的检查确实应该在这里空集去.换句话说:你是否研究过特征,并了解它们的整体概念; 你是否100%肯定在这里想要"无"?!

  • 不需要将`Set`存储到变量中.`Collections.emptySet()`已经返回存储在`Collections.EMPTY_SET`中的常量...... (2认同)