NullPointerException是RuntimeException的一个子类,这是运行时异常,在编译时期不会触发。
Java是没有指针的,所以我们常说"Java 指针"就是指"Java 的引用"。空指针就是空引用
,Java空指针异常就是引用本身为空,但却调用了方法,这个时候就会出现空指针异常。
成员变量和方法是属于对象的(除去静态的),在对象中才存在相对应的成员变量和方法,然后通过对象去调用这些成员变量和方法。
而对于空指针来说,它是不指向任何对象的,也就是没有所谓的成员变量和方法
,这个时候去调用某些属性和方法时,就一定会出现空指针异常。
/**
* @author QHJ
* @date 2021/11/25 14:42
* @description:
*/
public class NullPointTest {
private int a = 1;
private int b = 2;
public static void main(String[] args) {
NullPointTest nullPointTest1 = new NullPointTest();
System.out.println(nullPointTest1.a);
System.out.println(nullPointTest1.sum());
NullPointTest nullPointTest2 = null;
System.out.println(nullPointTest2.b);
System.out.println(nullPointTest2.sum());
}
public String sum(){
return "这是sum()方法...";
}
}
说明:对象 nullPointTest1 是通过默认的无参构造方法实例出来的 NullPointTest 对象;对象 nullPointTest2 只是声明了一个空对象,并没有指向实际的对象,它没有响应的成员变量和方法,当调用不属于它的成员变量和方法时,引发空指针异常。
null是Java中一个很重要的概念,null 设计的初衷是为了表示一些缺失的东西,比如缺失的用户、资源或一些其他东西。
首先,null是关键字
,像public、static、final。它是大小写敏感的,你不能将 null 写成 Null 或 NULL,编译器将不能识别它们然后报错。
null是任何引用类型的默认值
,不严格的说是所有object类型的默认值。就像你创建了一个布尔类型的变量,它将 false 作为自己的默认值,Java中的任何引用变量都将 nul l作为默认值。这对所有变量都是适用的,如成员变量、局部变量、实例变量、静态变量(但当你使用一个没有初始化的局部变量,编译器会警告你)。
null既不是对象也不是一种类型,它仅是一种特殊的值,你可以将其赋予任何引用类型,你也可以将 null 转化成任何类型。
null可以赋值给引用变量,但不能将null赋给基本类型变量。
例如int、double、float、boolean。编译器将会报错。
当直接将null赋值给基本类型,会出现编译错误。但是如果将null赋值给包装类object,然后将object赋给各自的基本类型,编译器不会报,但是你将会在运行时期遇到空指针异常。这是Java中的自动拆箱导致的。
如果使用了带有 null 值的引用类型变量,instanceof 操作将会返回 false。
Integer iAmNull = null;
if(iAmNull instanceof Integer){
System.out.println("iAmNull is instance of Integer");
}else{
System.out.println("iAmNull is NOT an instance of Integer");
}
结果:iAmNull is NOT an instance of Integer
不能调用非静态方法来使用一个值为 null 的引用类型变量。但是可以调用静态方法里值为 null 的引用类型变量,因为静态方法使用静态绑定,不会抛出空指针异常。
可以将 null 传递给方法使用,这时方法可以接收任何引用类型
,例如public void print(Object obj)可以这样调用print(null)。从编译角度来看这是可以的,但结果完全取决于方法。null 安全的方法,如在这个例子中的 print() 方法,不会抛出空指针异常,只是优雅的退出。如果业务逻辑允许的话,推荐使用 null 安全的方法。
可以使用 = = 或者 != 操作来比较 null 值
,但是不能使用其他算法或者逻辑操作,例如小于或者大于。在Java中 null == null 将返回true。
出现空指针
String str = null;
// 不推荐——把变量放在常量前,当变量为空时,运行时报空指针
if (str.equals("zhangsan")){
System.out.println("相等");
}else{
System.out.println("不相等");
}
避免空指针
String str = null;
// 推荐——把常量放在变量前,运行时不会报错
if ("zhangsan".equals(str)){
System.out.println("相等");
}else {
System.out.println("不相等");
}
出现空指针
// list1 没有使用具体的类进行初始化,在使用时会报错
List list1;
// list2 没有使用具体的类进行初始化,报空指针
List list2 = null;
System.out.println("不能直接使用list1...");
System.out.println("list2:" + list2.isEmpty());
避免空指针
List list3 = new ArrayList();
System.out.println("list3:" + list3.isEmpty());
出现空指针
Integer a = 1;
Integer b = null;
sum(a, b);
public static String sum(Integer a, Integer b){
System.out.println(a + b);
return "这是sum()方法...";
}
注意: null 值不能转换为基本数据类型!
避免空指针
Integer a = 1;
Integer b = null;
// 避免空指针——及时判空
if (a != null && b != null){
sum(a, b);
}else{
System.out.println("参数不允许为空值!");
}
public static String sum(Integer a, Integer b){
System.out.println(a + b);
return "这是sum()方法...";
}
出现空指针
UserEntity userEntity = null;
System.out.println(userEntity.getName() + "\t" +userEntity.getAge());
避免空指针
UserEntity userEntity = null;
if (userEntity != null){
System.out.println(userEntity.getName() + "\t" +userEntity.getAge());
}else {
System.out.println("对象不能为空哦!");
}
出现空指针
Map<String, String> map = new Hashtable<>();
map.put("name:", "张三");
map.put("age:", "23");
map.put("nick:", null);
map.put("", "");
System.out.println(map);
避免空指针
Map<String, String> map = new HashMap<>();
map.put("name:", "张三");
map.put("age:", "23");
map.put("nick:", null);
map.put("", "");
System.out.println(map);
出现空指针
// 假设是通过方法或远程调用获得的list
List list = null;
Stream stream = list.stream().filter(s -> s.equals("zhangsan"));
System.out.println(stream);
避免空指针
// 假设是通过方法或远程调用获得的list
List list = null;
if (list != null){
Stream stream = list.stream().filter(s -> s.equals("zhangsan"));
System.out.println(stream);
}else {
System.out.println("获取的集合list不能为空!");
}
在遇到空指针错误时,要重点关注报错发生的所在行,通过空指针异常产生的两条主要原因(变量未初始化和对象为空)诊断具体的错误,主要注意以下几点:
初始化
;避免在函数中返回 null 值
,如果必须要返回 null 值,一定要给出详细的注释信息;判空处理
(除非有明确的说明可以为 null );"常量在前变量在后"
的原则;使用 valueOf() 替换toString()
;Java中的8种数据类型,变量的值可以有其默认值,假如没有对其正常赋值,Java虚拟机是不能正确编译通过的,所以使用基本数据类型一般是不会引起空指针异常的。也就是说,在实际开发中大多数的空指针异常主要与对象的操作相关。