You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java Lambda按对象属性排序触发NullPointerException问题及解决咨询

问题:Java Lambda排序嵌套属性时使用nullsFirst仍触发空指针异常

场景描述

  • 按对象的嵌套属性Person.ageRange.begin排序,部分Person对象的ageRange为null,使用Comparator.nullsFirst()后仍抛出NullPointerException。

示例代码

import java.util.Comparator;
import java.util.stream.Collectors;
import java.util.List;
import java.util.ArrayList;

class HelloWorld {
    public static void main(String[] args) {
        AgeRange ageRange = new AgeRange();
        ageRange.setBegin(1);
        ageRange.setEnd(18);
        
        Person p1 = new Person();
        p1.setAgeRange(ageRange); // 修正原代码变量名错误:age -> ageRange
        
        Person p2 = new Person();
        p2.setAgeRange(null);
        
        AgeRange ageRange1 = new AgeRange();
        ageRange1.setBegin(19);
        ageRange1.setEnd(25);
        
        Person p3 = new Person();
        p3.setAgeRange(ageRange1);
        
        List<Person> persons = new ArrayList<>();
        persons.add(p1);
        persons.add(p2);
        persons.add(p3);
        
        persons.stream().sorted(Comparator.nullsFirst(Comparator.comparing(Person::getAgeRange)))
        .collect(Collectors.toList());
        // 此处抛出NullPointerException
    }
}

class Person {
    private String name;
    private AgeRange ageRange;
    
    public String getName(){
        return this.name;
    }
    
    public void setName(String name){
        this.name = name;
    }
    
    public AgeRange getAgeRange(){
        return this.ageRange;
    }
    
    public void setAgeRange(AgeRange ageRange){
        this.ageRange = ageRange;
    }
}

class AgeRange implements Comparable<AgeRange>{
    long begin;
    long end;
    
    public void setBegin(long begin){
        this.begin = begin;
    }
    
    public void setEnd(long end){
        this.end = end;
    }
    
    public long getBegin(){
        return this.begin;
    }
    
    public long getEnd(){
        return this.end;
    }
    
    @Override
    public int compareTo(AgeRange obj){
        return Long.compare(begin,obj.begin);
    }
}

异常信息

Exception in thread "main" java.lang.NullPointerException
at java.base/java.util.Comparator.lambda$comparing$77a9974f$1(Comparator.java:469)
at java.base/java.util.Comparators$NullComparator.compare(Comparators.java:83)
    at java.base/java.util.TimSort.countRunAndMakeAscending(TimSort.java:355)
    at java.base/java.util.TimSort.sort(TimSort.java:220)
    at java.base/java.util.Arrays.sort(Arrays.java:1515)
at java.base/java.util.stream.SortedOps$SizedRefSortingSink.end(SortedOps.java:353)
    at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:485)
    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 HelloWorld.main(HelloWorld.java:34)

问题原因

你当前的写法逻辑有误:

  • Comparator.nullsFirst()是用来处理被比较的Person对象本身为null的情况,但你的场景是Person对象不为null,只是它的ageRange属性为null。
  • 当调用Comparator.comparing(Person::getAgeRange)时,若某个Person的ageRange为null,comparing方法会尝试调用AgeRange的compareTo方法,此时传入的参数是null,直接触发空指针异常。

正确实现方式

方案1:用comparing重载方法处理嵌套属性的null值

直接在comparing中指定处理AgeRange null值的比较器,这是最简洁的写法:

persons.stream()
       .sorted(Comparator.comparing(
           Person::getAgeRange,
           Comparator.nullsFirst(Comparator.comparing(AgeRange::getBegin))
       ))
       .collect(Collectors.toList());
  • 第二个参数专门处理getAgeRange返回的null值:当ageRange为null时,nullsFirst会将其排在前面;非null时则按ageRange.begin排序。

方案2:手动编写lambda比较逻辑

如果需要更灵活的排序规则,可以直接写lambda处理所有情况:

persons.stream()
       .sorted((p1, p2) -> {
           if (p1.getAgeRange() == null && p2.getAgeRange() == null) {
               return 0;
           }
           if (p1.getAgeRange() == null) {
               return -1; // null优先排在前面
           }
           if (p2.getAgeRange() == null) {
               return 1;
           }
           return Long.compare(p1.getAgeRange().getBegin(), p2.getAgeRange().getBegin());
       })
       .collect(Collectors.toList());

补充:原代码编译错误修正

原代码中p1.setAgeRange(age);是变量名错误,需改为p1.setAgeRange(ageRange);才能正常编译。

内容的提问来源于stack exchange,提问作者Tim

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 19:30:54