Reputation: 13855
I have implemented a custom collector by implementing the Collector interface and overridding its methods. The Collector implementation is as follows:
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;
}
}
Here is my Person 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();
}
}
And Here is my calling statements...
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());
When the above statement gets executed, i got a NullPointerException as follows:
Exception in thread "main" java.lang.NullPointerException at java.util.stream.ReduceOps$3.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)
Can anybody tell where i am making the mistake?
Upvotes: 2
Views: 1599
Reputation: 140613
Here:
public Set<java.util.stream.Collector.Characteristics> characteristics() {
return null;
Return an empty set instead of null; like
private final static Set<Characteristics> EMPTY = Collections.emptySet();
...
return EMPTY;
or just
return Collections.emptySet();
(as the Collections class is already having some EMPTY constant on its own).
The core point is: this interface contains that method; and "I am not using this part" still requires you to "reasonably" implement that method. So keep that in mind for the future: any collection-returning interface allows for saying "no content" by returning an empty thing; instead of a null thing!
Of course, in the end the problem could be seen by the surrounding framework not checking if that method returns null. But as said: when you are dealing with collections of any kind, forget about using null. If there is nothing, create an empty collection object of that type!
One crucial step to avoid NPEs is by not returning null in the first place.
And beyond that: as Eugene is pointing out - you probably want to check really carefully of if you really should go with an empty Set here. In other words: did you look into Characteristics and do understand the whole concept of them; and are you 100% sure that want "none" here?!
Upvotes: 8