如何避免使用Collectors.summarizingInt时出现空指针异常 (NPE)。

huangapple go评论82阅读模式
英文:

How to avoid NPE with Collectors.summarizingInt

问题

我们的代码需要从类似以下代码的对象列表中返回最大值和最小值:

import java.util.IntSummaryStatistics;
import java.util.List;
import java.util.stream.Collectors;

public class Test {

    private Short attr;

    public Short getAttr() {
        return attr;
    }

    public static void main(String[] args) {
        List<Test> tests = List.of(new Test(), new Test());

        IntSummaryStatistics i = tests.stream()
                .map(Test::getAttr)
                .map(Integer::valueOf)
                .filter(in -> in != null && in > 0)
                .collect(Collectors.summarizingInt(Integer::intValue));

        System.out.println(i.getMax() + " " + i.getMin());
    }

}

我们如何避免空指针异常(NPE)?如果没有有效的属性(attrs),我们可以返回零的最大值和最小值。

异常信息:

Exception in thread "main" java.lang.NullPointerException
    at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:195)
    at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:195)
    at java.base/java.util.AbstractList$RandomAccessSpliterator.forEachRemaining(AbstractList.java:720)
    at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:484)
    at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474)
    at java.base/java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:913)
    at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
    at java.base/java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:578)
    at Test.main(Test.java:20)
英文:

Our code needs to return max and min values from a list of Objects pretty much alike the following code:

import java.util.IntSummaryStatistics;
import java.util.List;
import java.util.stream.Collectors;

public class Test {

    private Short attr;

    public Short getAttr() {
        return attr;
    }

    public static void main (String[] args) {
        List&lt;Test&gt; tests = List.of(new Test(), new Test());

        IntSummaryStatistics i = tests.stream()
                .map(Test::getAttr)
                .map(Integer::valueOf)
                .filter(in -&gt; in != null &amp;&amp; in &gt; 0)
                .collect(Collectors.summarizingInt(Integer::intValue));

        System.out.println(i.getMax() + &quot; &quot; + i.getMin());
    }

}

How could we avoid NPE (null pointer exception)? In case of no valid attrs we can return zero max and min.

Exception message:

Exception in thread &quot;main&quot; java.lang.NullPointerException
at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:195)
at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:195)
at java.base/java.util.AbstractList$RandomAccessSpliterator.forEachRemaining(AbstractList.java:720)
at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:484)
at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474)
at java.base/java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:913)
at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
at java.base/java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:578)
at Test.main(Test.java:20)

答案1

得分: 3

NPE 在以下代码中被抛出:

   .map(Integer::valueOf)

因为 Integer#valueOf(int) 会对输入进行拆箱操作,可能导致 NPE(空指针异常)。

为了解决这个问题,我建议采取以下其中一种方法。

  1. (由 Holger 提出的建议)删除 .map(Integer::valueOf) 这部分,并且在 Collectors.summarizingInt 内部将 Short 映射为 int(使用 Short::intValue),如下所示:
IntSummaryStatistics i = tests.stream()
                .map(Test::getAttr)
                .filter(in -> in != null && in > 0)
                .collect(Collectors.summarizingInt(Short::intValue));

请注意,当流为空时,IntSummaryStatistics#getMaxgetMin 将分别为 Integer.MIN_VALUEInteger.MAX_VALUE不直观!!)。

因此输出将会是 -2147483648 2147483647

  1. attr 提供一个默认值(也许是 0)。
英文:

The NPE is thrown in

   .map(Integer::valueOf)

as Integer#valueOf(int) will unbox the input and cause NPE.
To solve the problem, I suggest one of the following way.

  1. (Suggested by Holger) Delete .map(Integer::valueOf) and map Short to int (Short::intValue) inside Collectors.summarizingInt as follow:
IntSummaryStatistics i = tests.stream()
                .map(Test::getAttr)
                .filter(in -&gt; in != null &amp;&amp; in &gt; 0)
                .collect(Collectors.summarizingInt(Short::intValue));

Please note that IntSummaryStatistics#getMax and getMin will be Integer.MIN_VALUE and Integer.MAX_VALUE respectively (not intuitive!!) when the stream is empty.
Hence the output will be -2147483648 2147483647.

  1. Provide default value (maybe 0) for attr.

huangapple
  • 本文由 发表于 2020年10月16日 08:41:14
  • 转载请务必保留本文链接:https://go.coder-hub.com/64381449.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定