Java 8 Stream - 使用自定义收集器时出现 NullPointerException
Java 8 Stream - NullPointerException when working with Custom Collector
我通过实现 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;
}
}
这是我的人class:
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();
}
}
这是我的调用语句...
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());
当上面的语句被执行时,我得到一个 NullPointerException 如下:
Exception in thread "main" java.lang.NullPointerException
at java.util.stream.ReduceOps.getOpFlags(ReduceOps.java:185)
at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
at java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:499)
at com.my.j8.TestStreams.main(TestStreams.java:231)
谁能告诉我哪里出错了?
这里:
public Set<java.util.stream.Collector.Characteristics> characteristics() {
return null;
Return 一个 empty 集而不是 null;喜欢
private final static Set<Characteristics> EMPTY = Collections.emptySet();
...
return EMPTY;
或者只是
return Collections.emptySet();
(因为集合 class 本身已经有一些 EMPTY 常量)。
核心点是:这个接口包含那个方法; "I am not using this part" 仍然需要您 "reasonably" 实施该方法。所以在未来记住这一点:any collection-returning 接口允许通过返回一个 empty 东西来表示 "no content";而不是 null 东西!
当然,最终问题可以被周围的框架而不是检查是否该方法returns null。但如前所述:当您处理任何类型的集合时,忘记 使用 null。如果没有,就创建一个empty那个类型的集合对象!
避免 NPE 的一个关键步骤是首先不返回 null。
除此之外:正如 Eugene 所指出的那样 - 您可能需要非常仔细地检查您是否 真的 应该在这里使用一个空的 Set。换句话说:您是否研究过 Characteristics 并理解它们的整个概念;您是否 100% 确定要 "none" 在这里?!
我通过实现 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;
}
}
这是我的人class:
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();
}
}
这是我的调用语句...
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());
当上面的语句被执行时,我得到一个 NullPointerException 如下:
Exception in thread "main" java.lang.NullPointerException at java.util.stream.ReduceOps.getOpFlags(ReduceOps.java:185) at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) at java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:499) at com.my.j8.TestStreams.main(TestStreams.java:231)
谁能告诉我哪里出错了?
这里:
public Set<java.util.stream.Collector.Characteristics> characteristics() {
return null;
Return 一个 empty 集而不是 null;喜欢
private final static Set<Characteristics> EMPTY = Collections.emptySet();
...
return EMPTY;
或者只是
return Collections.emptySet();
(因为集合 class 本身已经有一些 EMPTY 常量)。
核心点是:这个接口包含那个方法; "I am not using this part" 仍然需要您 "reasonably" 实施该方法。所以在未来记住这一点:any collection-returning 接口允许通过返回一个 empty 东西来表示 "no content";而不是 null 东西!
当然,最终问题可以被周围的框架而不是检查是否该方法returns null。但如前所述:当您处理任何类型的集合时,忘记 使用 null。如果没有,就创建一个empty那个类型的集合对象!
避免 NPE 的一个关键步骤是首先不返回 null。
除此之外:正如 Eugene 所指出的那样 - 您可能需要非常仔细地检查您是否 真的 应该在这里使用一个空的 Set。换句话说:您是否研究过 Characteristics 并理解它们的整个概念;您是否 100% 确定要 "none" 在这里?!