O Java 8 Collectors.toMap
lança a NullPointerException
se 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.
null
pode ser um problema para uma chave, mas, neste caso, é o valor.
null
, HashMap
por exemplo, podem ter uma null
chave e qualquer número de null
valores, você pode tentar criar um personalizado Collector
usando a em HashMap
vez de usar o padrão.
HashMap
- como mostrado na primeira linha do stacktrace. O problema não é que um valor Map
não pode conter null
, mas que o segundo argumento da Map#merge
função não pode ser nulo.
null
sempre foi um pouco problemático, como no TreeMap. Talvez um bom momento para experimentarOptional<Boolean>
? Caso contrário, divida e use o filtro.