网罗开发 (小红书、快手、视频号同名)

  大家好,我是 展菲,目前在上市企业从事人工智能项目研发管理工作,平时热衷于分享各种编程领域的软硬技能知识以及前沿技术,包括iOS、前端、Harmony OS、Java、Python等方向。在移动端开发、鸿蒙开发、物联网、嵌入式、云原生、开源等领域有深厚造诣。

图书作者:《ESP32-C3 物联网工程开发实战》
图书作者:《SwiftUI 入门,进阶与实战》
超级个体:COC上海社区主理人
特约讲师:大学讲师,谷歌亚马逊分享嘉宾
科技博主:华为HDE/HDG

我的博客内容涵盖广泛,主要分享技术教程、Bug解决方案、开发工具使用、前沿科技资讯、产品评测与使用体验。我特别关注云服务产品评测、AI 产品对比、开发板性能测试以及技术报告,同时也会提供产品优缺点分析、横向对比,并分享技术沙龙与行业大会的参会体验。我的目标是为读者提供有深度、有实用价值的技术洞察与分析。

展菲:您的前沿技术领航员
👋 大家好,我是展菲!
📱 全网搜索“展菲”,即可纵览我在各大平台的知识足迹。
📣 公众号“Swift社区”,每周定时推送干货满满的技术长文,从新兴框架的剖析到运维实战的复盘,助您技术进阶之路畅通无阻。
💬 微信端添加好友“fzhanfei”,与我直接交流,不管是项目瓶颈的求助,还是行业趋势的探讨,随时畅所欲言。
📅 最新动态:2025 年 3 月 17 日
快来加入技术社区,一起挖掘技术的无限潜能,携手迈向数字化新征程!


摘要

在 Java 开发中,NullPointerException(空指针异常) 是最常见也是最让人头疼的异常之一。它通常出现在你操作了一个还没有初始化的对象时。很多同学写项目,尤其是初学时,总会碰到 “空指针” 的报错,明明逻辑没什么问题,结果程序直接崩掉。今天我们就用一个简单的例子,聊聊空指针出现的原因、常见的解决方法,并写个小 Demo 帮助你更好地理解。

引言

Java 的对象在使用之前必须先实例化,这跟 Python、JavaScript 等动态语言有点不一样。在动态语言中,即使你没有定义变量也可能会被“兜底”处理掉,但在 Java 里,一旦你直接对 null 调用方法,就会触发 NullPointerException
所以空指针本质上就是:你把不存在的东西,当作存在的对象来用

问题分析

来看下面这段代码:

public class NullPointerDemo {
    public static void main(String[] args) {
        String s = null;
        System.out.println(s.length());
    }
}

运行结果:

Exception in thread "main" java.lang.NullPointerException
    at NullPointerDemo.main(NullPointerDemo.java:4)

这里 snull,却调用了 s.length(),于是程序直接抛出了空指针异常。

很多新手在实际开发中,可能是在处理请求参数、数据库返回值、或者第三方接口返回对象时,忘记做空值检查,就导致了这种问题。比如:

  • 数据库没查到数据返回 null
  • HTTP 接口没返回期望字段;
  • 集合里没有元素直接调用 .get(0)
  • Spring 注入失败,Bean 没有实例化。

常见解决方案

1. 手动判空(最朴素的方法)

public class NullPointerCheck {
    public static void main(String[] args) {
        String s = null;
        if (s != null) {
            System.out.println(s.length());
        } else {
            System.out.println("字符串为空,无法计算长度");
        }
    }
}

解释:
这是最常见的防御性写法。在调用对象的方法之前先做空值判断,可以避免异常直接崩掉程序。

2. 使用 Optional(推荐写法)

Java 8 引入了 Optional,它的核心思想是:把可能为空的对象用一个容器包起来,强制你用显式的方式处理空值

import java.util.Optional;

public class NullPointerOptional {
    public static void main(String[] args) {
        String s = null;

        // 用 Optional 包裹
        String result = Optional.ofNullable(s)
                .map(String::length)   // 如果不为 null,就计算长度
                .map(Object::toString) // 转成字符串
                .orElse("默认值");      // 如果为 null,返回默认值

        System.out.println(result);
    }
}

输出:

默认值

解释:
相比传统 if (obj != null)Optional 写法更优雅,更函数式,也能让代码逻辑更清晰。

3. 使用 Lombok 的 @NonNull 注解(开发时防御)

Lombok 提供了一个 @NonNull 注解,可以在方法参数或成员变量上标记。被标记的参数如果传入了 null,在运行时会自动抛出 NullPointerException,帮助你更快定位问题。

import lombok.NonNull;

public class NullPointerLombok {

    public static void printLength(@NonNull String s) {
        System.out.println(s.length());
    }

    public static void main(String[] args) {
        String value = null;
        printLength(value); // 这里会直接抛 NullPointerException
    }
}

输出:

Exception in thread "main" java.lang.NullPointerException: s is marked non-null but is null

解释:
这不是帮你避免空指针,而是 在第一时间发现空指针,防止错误逻辑蔓延到更深层。

实际开发场景举例

场景 1:数据库查询结果为空

User user = userRepository.findById(123);
if (user != null) {
    System.out.println(user.getName());
} else {
    System.out.println("用户不存在");
}

场景 2:第三方接口返回字段缺失

ApiResponse response = apiClient.getUserInfo();
Optional.ofNullable(response.getData())
        .map(UserData::getNickname)
        .ifPresentOrElse(
            nickname -> System.out.println("昵称:" + nickname),
            () -> System.out.println("接口返回数据为空")
        );

场景 3:集合取值前检查

List<String> list = new ArrayList<>();
if (!list.isEmpty()) {
    System.out.println(list.get(0));
}

QA 环节

Q:为什么有时候明明加了 @Autowired,还是报空指针?
A:这通常是因为 Spring 的 Bean 没有被扫描到,或者你在非 Spring 管理的类里使用了 Bean。解决办法是检查包扫描路径,或者用 @Component / @Service 标注类。

Q:Optional 会不会影响性能?
A:Optional 本质上是个对象包装,开销很小,一般业务代码中性能损耗可以忽略不计。

总结

  • 空指针异常本质上就是你在操作 null 对象
  • 最简单的方法是 手动判空
  • 推荐使用 Optional 让代码更简洁。
  • 可以用 Lombok 的 @NonNull 提前发现空值问题。
  • 在实际项目中,不同场景需要结合判空逻辑,养成良好的防御性编程习惯。
Logo

加入「COC·上海城市开发者社区」,成就更好的自己!

更多推荐