0

Why is Collectors.groupingBy throwing NullPointerException?

Caused by: java.lang.NullPointerException
        at java.util.stream.Collectors.lambda$groupingBy$45(Collectors.java:907)
        at java.util.stream.ReduceOps$3ReducingSink.accept(ReduceOps.java:169)
        at java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1374)
        at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:481)
        at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471)
        at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:708)
        at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
        at java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:499)
        at com.evry.integrator.terpcrm.schedular.CustomerTeamsJmsServiceImpl.importDataFromTerpAndNotifyTopic(CustomerTeamsJmsServiceImpl.java:90)

Composite Key:

 //Entity with Getter and setters
public String getCompositeKey() {
    return getRegistryId() + "_" + getPersonPartyId() + "_" + getSource()+ "_" + getRoleName();
}

//Earlier following was composite key and it works fine; when added another field...NPE but when i revert to following no issues
//public String getCompositeKey() {
//  return getRegistryId() + "_" + getPersonPartyId() + "_" + getSource();
//}

Code to find duplicates in table based on composite key which was working fine earlier, but now adding another field throws an NPE: (there are no nulls present in DB)

Set<String> duplicates  = xxedgeCrtV.stream()
                    .collect(Collectors.groupingBy(XxedgeCrtV::getCompositeKey, Collectors.counting()))
                    .entrySet().stream()
                    .filter(e -> e.getValue() > 1L)
                    .map(e -> e.getKey())
                    .collect(Collectors.toSet());

More data:

Out of 40,000 records; 10 records are there with getRoleName as null, but when I query the count by grouping by all four, then it does not return any record, which means all are.

In void main, when I try following, no NullPointerException:

        String a = null;
        String b = "gigi";
        String c = "migi";
        String d = "figi";
        System.out.println(d+ "_" + c+ "_" +b + "_"+a);
         Output: figi_migi_gigi_null

Note:

I have handled getRoleName null case, but still same issue.

Mark Rotteveel
  • 100,966
  • 191
  • 140
  • 197
fatherazrael
  • 5,511
  • 16
  • 71
  • 155
  • 1
    Maybe there's a null element in the list (is it a list?) you are streaming – fps Oct 29 '20 at 04:39
  • 1
    Or maybe getRegistryId() returns null – fps Oct 29 '20 at 04:47
  • @fps: Yes it is list. Loaded from DB directl. In which i have written getCompositeKey(). getRegistryID is not null in table. Only 10 records of getRolename are null. – fatherazrael Oct 29 '20 at 05:04
  • 2
    Do this: `xxedgeCrtV.stream().filter(o -> o == null).count()` and see if it's 0 – fps Oct 29 '20 at 05:32
  • @fps: Correct direction. It was because getRoleName() ID was null. Data corrected and issue gone. In Composite Key, if we have NULL then we have NULL row added to arraylist. – fatherazrael Oct 29 '20 at 09:04
  • 3
    I hate to repeat myself, but using string concatenation for composite keys is a) error prone (what if any string contains a `_`?) and b) horribly inefficient (every string concatenation bears a copying of all strings’ characters and requires additional memory in that scale—for every element). In contrast, a composition like `Arrays.asList(getRegistryId(), getPersonPartyId(), getSource(), getRoleName())` bears no ambiguity and holds the strings by reference. – Holger Oct 29 '20 at 09:44
  • 4
    Besides, you don’t need to count, when you only want to know whether there’s more than one. You can use `… .collect(Collectors.toMap(XxedgeCrtV::getCompositeKey, x -> false, (a, b) -> true)) .entrySet().stream() .filter(e -> e.getValue()) .map(e -> e.getKey()) …` instead. It produces a `Boolean` value in the first place. – Holger Oct 29 '20 at 09:47
  • @Holger: a) error prone: Not in my case, as if it will be _ and _ ; i am using to compare same record entity in my table and it will also return _ and _ b) you are correct; will use StringBuilder as quick solution. Arrays.asList not sure how to compare that. Will check code too. Thanks for another suggestion. I will try that too/ – fatherazrael Oct 29 '20 at 17:35
  • 1
    Using StringBuilder does not solve any problems, it still implies copying all character data. In fact, prior to JDK 9, the string concatenation will be compiled to code using StringBuilder, so the result will be identical. – Holger Nov 24 '20 at 11:10

0 Answers0