最安全的方式是用 list != null && !list.isEmpty() 短路表达式,确保集合非空时才执行后续操作;避免分步判空导致NPE,推荐返回空集合而非null,并在方法入口用 Objects.requireNonNull() 校验入参。
用 && 把集合判空和后续操作写在同一表达式里,就能在集合为 null 时跳过取值或遍历,天然拦截空指针风险。
判空与遍历必须写在同一个表达式中
短路保护只在单个布尔表达式内生效。只要把集合非空检查和它的使用绑在一起,就能确保安全:
- ✅ 安全:
if (list != null && !list.isEmpty()) { process(list.get(0)); }—— list 为 null 时,!list.isEmpty()根本不执行 - ❌ 危险:
if (list != null) { if (list.isEmpty()) { ... } }—— 看似判了空,但后续若单独写list.size()或list.forEach(...),仍可能 NPE
避免返回 null 集合,从源头切断风险
方法返回集合时,别返回 null,改用标准空集合:
- 用
Collections.emptyList()、Collections.emptySet()或Collections.emptyMap()替代return null; - 调用方拿到的是真实集合对象,可直接调用
.size()、.stream()、.forEach(),无需任何判空 - 若业务需区分“无数据”和“未初始化”,应靠状态字段或枚举表达,而非用
null做语义载体
入参校验放在方法最开头
对传入的集合参数,第一时间用 Objects.requireNonNull() 拦截:
public void handleUsers(List<user> users) { Objects.requireNonNull(users, "users must not be null"); ... }</user>- 这样既明确契约,又让错误堆栈指向调用点,而不是深埋在某次
get(0)里 - 如果允许空集合但不允许
null,这一步就够了;若空集合也非法,再加if (users.isEmpty()) throw ...
链式操作中逐级用 && 守住每一道门
访问嵌套集合结构(如 user.getOrders().get(0).getItems())时,不能只判最外层:
- ✅ 正确:
if (user != null && user.getOrders() != null && !user.getOrders().isEmpty() && user.getOrders().get(0) != null && user.getOrders().get(0).getItems() != null) - 每一环都是前一环成立的前提,任一为 false,后面全部跳过
- 嵌套太深时建议改用 Optional 或工具类(如 Apache Commons 的
ObjectUtils.firstNonNull()),但短路逻辑仍是底层基础

















