O Java 8 Collectors.toMaplança a NullPointerExceptionse um dos valores for 'nulo'. Eu não entendo esse comportamento, os mapas podem conter ponteiros nulos como valor sem problemas. Existe uma boa razão pela qual os valores não podem ser nulos Collectors.toMap?
Além disso, existe uma maneira agradável do Java 8 de corrigir isso, ou devo reverter para o antigo loop for?
Um exemplo do meu problema:
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
class Answer {
private int id;
private Boolean answer;
Answer() {
}
Answer(int id, Boolean answer) {
this.id = id;
this.answer = answer;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public Boolean getAnswer() {
return answer;
}
public void setAnswer(Boolean answer) {
this.answer = answer;
}
}
public class Main {
public static void main(String[] args) {
List<Answer> answerList = new ArrayList<>();
answerList.add(new Answer(1, true));
answerList.add(new Answer(2, true));
answerList.add(new Answer(3, null));
Map<Integer, Boolean> answerMap =
answerList
.stream()
.collect(Collectors.toMap(Answer::getId, Answer::getAnswer));
}
}
Stacktrace:
Exception in thread "main" java.lang.NullPointerException
at java.util.HashMap.merge(HashMap.java:1216)
at java.util.stream.Collectors.lambda$toMap$168(Collectors.java:1320)
at java.util.stream.Collectors$$Lambda$5/1528902577.accept(Unknown Source)
at java.util.stream.ReduceOps$3ReducingSink.accept(ReduceOps.java:169)
at java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1359)
at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:512)
at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:502)
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 Main.main(Main.java:48)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:483)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:134)
Esse problema ainda existe no Java 11.
nullpode ser um problema para uma chave, mas, neste caso, é o valor.
null, HashMappor exemplo, podem ter uma nullchave e qualquer número de nullvalores, você pode tentar criar um personalizado Collectorusando a em HashMapvez de usar o padrão.
HashMap- como mostrado na primeira linha do stacktrace. O problema não é que um valor Mapnão pode conter null, mas que o segundo argumento da Map#mergefunção não pode ser nulo.
nullsempre foi um pouco problemático, como no TreeMap. Talvez um bom momento para experimentarOptional<Boolean>? Caso contrário, divida e use o filtro.