读者被问题代码折磨,鸭哥劝 NullPointerException 耗子尾汁!!!

简介: 说起来,鸭哥也算是身经百战的码农了,代码习惯和风格都是不错的。没想到,今天大意了没有闪,NullPointerException 就找上门来了。

image.png

看完问题鸭哥想说,NullPointerException 确实不讲武德,小伙子大意了没有闪,鸭哥来帮你解决~

题目如下:

//不讲武德的代码
public class Printer {
    private String name;
    public void setName(String name) {
        this.name = name;
    }
    public void print() {
        printString(name);
    }
    private void printString(String s) {
        System.out.println(s + " (" + s.length() + ")");
    }
    public static void main(String[] args) {
        Printer printer = new Printer();
        printer.print();
    }
}

运行结果:

Exception in thread "main" java.lang.NullPointerException
    at Printer.printString(Printer.java:13)
    at Printer.print(Printer.java:9)
    at Printer.main(Printer.java:19)


根据报错信息(stacktrace),可以顺藤摸瓜,找出问题所在:

  1. 程序的编译没有问题,编译后运行,线程"main"抛出了 NullPointerException 空指针异常;
  2. 继续往下看,新建的对象 printer 调用 printString 方法时,第 13 行代码抛出了异常,出现问题的代码是  s.length() ;
  3. 执果索因,printString 方法中,s 的值从何而来呢?是在 print() 方法中通过 调用printString(name) 传入的。检查后可以发现,问题在于 this.name 为 null;
  4. 问题找到了,由于新建对象时没有初始化,调用了 null 的实例方法,导致抛出了异常。


正确的代码如下:


public class Printer {
    private final String name;
    public Printer(String name) {
        this.name = Objects.requireNonNull(name);
    }
    public void print() {
        printString(name);
    }
    private void printString(String s) {
        System.out.println(s + " (" + s.length() + ")");
    }
    public static void main(String[] args) {
        Printer printer = new Printer("123");
        printer.print();
    }
}


故事到这里似乎就结束了,但俗话说吃一堑长一智,鸭哥还是要继续扒一下 NullPointerException 。


在Java中,当我们用如下方式声明一个基本数据类型的变量时。


int x;
x = 1;


第一行,声明了 int 型变量 x,且 Java 会将 x 的值初始化为 0;


第二行,将 10 赋值给 x,10这个数值会被写入变量 x 指向的内存中。但当我们用类似的方式声明一个引用数据类型的对象时,Java执行的操作并不相同


Integer num;
num = new Integer(1);


第一行,声明了 num 变量,但因为 Integer 属于引用类型,此时 num 并不包含数值,而是一个指针,并且指针的值为 null, 即空指针,不指向任何地址;


第二行,先是创建了一个 Integer 对象,然后将 num 变量指向了该对象。


当我们声明了一个引用类型的变量,却没有创建指向该变量的对象,此时访问这个变量的内容或调用它的实例方法,就会抛出 NullPointerException (NPE)  异常,因为我们要访问的内容实际上并不存在。


常见的处理方式是,先判断参数是否为空,非空时再进行接下来的处理,模式如下:


public void doSomething(someObject obj) {
    if(obj == null) {
       // Do something
    } else {
       // Do something else
    }
}


最后,鸭哥想说,应对 NullPointerException (NPE)  的最有效方法就是:


所有不是我们自己创建的对象,一律检查该对象是否为空


如果是调用者给某方法传入了无效参数,最好将抛出的异常返回给调用者。忽略无效参数且不做任何处理是最不可取的,因为这样做隐藏了问题,后续出错时再排查会相当困难。


关于 NullPointerException,你有哪些注意事项想要分享给大家呢?


相关文章
|
6月前
|
Java 程序员 编译器
【Java开发指南 | 第二十三篇】Java异常处理
【Java开发指南 | 第二十三篇】Java异常处理
40 1
|
6月前
|
Java 程序员 数据安全/隐私保护
Java中的异常语法知识居然这么好玩!后悔没有早点学习
Java中的异常语法知识居然这么好玩!后悔没有早点学习
66 1
|
人工智能 程序员 vr&ar
竟有程序员40了还在撸代码?
竟有程序员40了还在撸代码?
148 2
|
前端开发 Java Spring
求求你不要写满屏的 try...catch 了,这才是优雅的处理方式,真香...
求求你不要写满屏的 try...catch 了,这才是优雅的处理方式,真香...
270 0
求求你不要写满屏的 try...catch 了,这才是优雅的处理方式,真香...
|
Java
Java福尔摩斯的约会大侦探福尔摩斯接到一张奇怪的字条:“我们约会吧 3485djDkxh4hhGE 2984akDfkkkkggEdsb s&hgsfdk d&Hyscvnm”。大侦探很快就明白了
Java福尔摩斯的约会大侦探福尔摩斯接到一张奇怪的字条:“我们约会吧 3485djDkxh4hhGE 2984akDfkkkkggEdsb s&hgsfdk d&Hyscvnm”。大侦探很快就明白了
133 0
Java福尔摩斯的约会大侦探福尔摩斯接到一张奇怪的字条:“我们约会吧 3485djDkxh4hhGE 2984akDfkkkkggEdsb s&hgsfdk d&Hyscvnm”。大侦探很快就明白了
|
Java API 容器
遇到空指针(npe)切莫慌 ✨ jdk 8中有妙招 ✨ 每日积累
遇到空指针(npe)切莫慌 ✨ jdk 8中有妙招 ✨ 每日积累
遇到空指针(npe)切莫慌 ✨ jdk 8中有妙招 ✨ 每日积累
|
缓存 监控 程序员
程序员的自我修养--读书笔记 (跑路人笔记)
程序员的自我修养--读书笔记 (跑路人笔记)
程序员的自我修养--读书笔记 (跑路人笔记)
|
存储 缓存 JavaScript
想好怎么学 Servlet规范了嘛?想好了嘛?没想好先看看这篇文章(爆肝之作),先看着然后慢慢想!!
Servlet(Server Applet)是Java Servlet的简称,称为小服务程序或服务连接器,用Java编写的服务器端程序,具有独立于平台和协议的特性,主要功能在于交互式地浏览和生成数据,生成动态Web内容。 狭义的Servlet是指Java语言实现的一个接口,广义的Servlet是指任何实现了这个Servlet接口的类,一般情况下,人们将Servlet理解为后者。Servlet运行于支持Java的应用服务器中。从原理上讲,Servlet可以响应任何类型的请求,但绝大多数情况下Servlet只用来扩展基于HTTP协议的Web服务器。
想好怎么学 Servlet规范了嘛?想好了嘛?没想好先看看这篇文章(爆肝之作),先看着然后慢慢想!!
|
Java 程序员
学妹问我Java异常是怎么回事,讲了半夜才明白,速度收藏!!!记得点赞和关注
异常是Java开发中常见的,也是程序最不愿意看到的,因为有异常基本上就代表我们写的代码有bug,很烦,游戏服务端有异常上报系统,每当半夜收到异常上报都慌的一笔。今天就扒一扒异常,开始走起。
148 0
学妹问我Java异常是怎么回事,讲了半夜才明白,速度收藏!!!记得点赞和关注
|
Java
老爷子这代码,看跪了! (上)
老爷子这代码,看跪了! (上)
147 0
老爷子这代码,看跪了! (上)

相关实验场景

更多