Java mapToLong不使用';后的过滤器非空;行不通

Java mapToLong不使用';后的过滤器非空;行不通,java,lambda,filter,Java,Lambda,Filter,我的密码是这样的 class A { private Long b; public Long getB() { return b; } public void setB(Long b) { this.b = b; } public static void main(String[] args) { A a1 = new A(); List<A> list = new

我的密码是这样的

class A {
    private Long b;

    public Long getB() {
        return b;
    }

    public void setB(Long b) {
        this.b = b;
    }

    public static void main(String[] args) {
        A a1 = new A();
        List<A> list = new ArrayList<>();
        list.add(a1);
        list.stream().mapToLong(A::getB).filter(Objects::nonNull).sum();
    }
}

它工作得很好。我想知道原因。

mapToLong
Long
转换为
Long
——如果
null
,您确实会得到一个异常

在转换之前,您需要过滤
null
s

list.stream()
    .map(A::getB)
    .filter(Objects::nonNull)   //filter the nulls first
    .mapToLong(Long::longValue) //then convert to primitive
    .sum();

tolong函数
传递给
mapToLong
函数,这是它的签名

long applyAsLong(T value);
传递方法引用
A::getB
——这里,它接受
b
,并通过取消装箱返回它(从
Long
转换为primitive
Long
)。因为它是空的,所以会导致NPE

通过更早地进行过滤,可以避免这种情况的发生

请参见:

此处

list.stream().mapToLong(A::getB).filter(Objects::nonNull).sum();
您正在尝试将列表中的每一个B转换为Long,然后不过滤空值。现在您正在尝试转换空值,因为您尚未筛选空值。这会引发NullPointerException

这里

您不过滤空值,然后映射并将其转换为长值。当您尝试转换时,这里没有空值,因为您已经过滤了它们,所以也没有空值异常。

为什么此代码失败

list.stream().mapToLong(A::getB).filter(Objects::nonNull).sum();
因为流操作是按顺序执行的。因此,如果流
A::getB
的任何元素没有返回NOTNULL
Long
,则在收集过程中会引发异常

为什么成功

list.stream().filter(a -> a.getB()!=null).mapToLong(A::getB).sum();
因为第一次执行的
filter()
会删除导致
a::getB
操作的空元素。 因此,在收集流中只添加NOTNULL元素。所以也不例外。 但问题是您执行了两次映射
a::getB
。即使在这里它并不昂贵(只是一种消遣),但它仍然是如此的无助。
你想要的是:

list.stream()       
    .map(A::getB) // return Stream<Long> that may contain null
    .filter(Objects::nonNull) // filter null elements
    .mapToLong(s->s) // map Long to long
    .sum(); // sum
list.stream()
.map(A::getB)//返回可能包含null的流
.filter(Objects::nonNull)//筛选空元素
.mapToLong(s->s)//从长到长映射
.sum();//总和

事实上,我认为它不能满足OP要求。如果比较工作和不工作示例,我们猜测
null
来自原始列表中的
A::getB
映射,而不是
null A
元素。
list.stream().filter(a -> a.getB()!=null).mapToLong(A::getB).sum();
list.stream()       
    .map(A::getB) // return Stream<Long> that may contain null
    .filter(Objects::nonNull) // filter null elements
    .mapToLong(s->s) // map Long to long
    .sum(); // sum