Recently, while working with Java 8 threads, I encountered a NullPointerException during a shrink operation while working with the following test cases:
private static final BinaryOperator<Integer> sum = (a, b) -> { if (a == null) return b; if (b == null) return a; return Integer.sum(a, b); }; List<Integer> s = new ArrayList<>(); s.add(null); s.add(null); s.add(null); Integer i = s.stream().reduce(sum).orElse(null); // throws NPE Integer i = s.stream().reduce(sum).orElse(2); // throws NPE Integer i = s.stream().reduce(null,(a, b)->null); // returns a value ie null
Or alternatively:
Integer i = s.stream().filter(Objects::nonNull).reduce(Integer::sum).orElse(null);
After checking the reduction operation, I came across this class that performs the reduction operation:
class ReducingSink implements AccumulatingSink<T, Optional<T>, ReducingSink> { private boolean empty; private T state; public void begin(long size) { empty = true; state = null; } @Override public void accept(T t) { if (empty) { empty = false; state = t; } else { state = operator.apply(state, t); } } @Override public Optional<T> get() { return empty ? Optional.empty() : Optional.of(state); } @Override public void combine(ReducingSink other) { if (!other.empty) accept(other.state); } }
In the above code, you will see that the get() method returns an optional value if boolean empty is false, and in my case false, and state is null, so Optional.of(null) throws a NullPointerException . In my case, I have a binary operator that allows null .
So, I think the code
return empty ? Optional.empty() : Optional.of(state);
should be changed to
return empty || state == null ? Optional.empty() : Optional.of(state);
Like my binary operator (which has the task of decreasing), and this is normal with null .