null 的安全操作 vs 危险操作

1. 完全安全的操作(不会NPE)
操作类型 示例代码 说明
单纯赋值 ListNode a = null; 直接赋null值完全合法
引用传递 headB = headB.next; 即使headB.nextnull也安全
判等比较 if(headB == null) 判断是否为null不会引发NPE
方法内参数传递 someMethod(headB.next); 仅传递引用,不访问成员
2. 会引发NPE的危险操作
操作类型 示例代码 触发条件
访问成员变量 int val = headB.val; headBnull
调用方法 headB.toString(); headBnull
链式属性访问 int val = headB.next.val; headBheadB.nextnull
数组访问 int[] arr = null; arr[0] = 1; arrnull

关键区分原则

  1. 仅操作引用本身(安全):

    • 赋值、传参、比较等操作只涉及引用变量本身,不访问对象内部

    • 示例:

      ListNode a = null;    // 安全
      ListNode b = a;       // 安全(b也变为null)
      if(a == null) {...}   // 安全
  2. 访问引用指向的对象(危险):

    • 任何试图通过引用访问对象成员(字段/方法)的操作

    • 示例:

      a.val;       // 危险!若a为null则NPE
      a.next.val;  // 双重危险!若a或a.next为null则NPE

链表操作中的典型场景

✅ 安全操作(无需判空)
// 移动指针(即使.next返回null)
while(current != null) {
    current = current.next;  // 安全!
}
❌ 危险操作(必须判空)
// 访问节点值
if(current.next.val > 0) {  // 需要先检查current.next!
    // ...
}

// 正确写法
if(current.next != null && current.next.val > 0) {
    // ...
}

特殊案例解析

案例1:方法调用中的null传递
void process(ListNode node) {
    System.out.println(node);  // 打印null是安全的
    System.out.println(node.val);  // NPE!
}

process(headB.next);  // 仅传递引用,不立即报错
案例2:三目运算符的短路特性
// 安全写法(等效于if-else)
ListNode next = (current != null) ? current.next : null;

记忆技巧

  1. "点号"警示原则

    • 看到 .(如 obj.xxx)就要警惕可能NPE

    • 除非 . 前面是class/static成员(如 Math.PI

  2. 操作类型速查表

    操作符/语法 是否可能NPE 示例
    = a = b
    ==/!= if(a == null)
    instanceof if(a instanceof X)
    .(成员访问) a.val
    [](数组访问) arr[0]

终极总结

  • 安全区:所有不涉及访问对象内部的操作(赋值、比较、传参)

  • 危险区:任何试图通过引用访问对象数据的操作(字段、方法、数组)

  • 链表编程口诀

    "移动指针不需慌,访问数据要验null"

你可能感兴趣的:(java,开发语言)