空指针异常与Optional类
一、什么是空指针异常
当程序需要对象实例的时候返回null
就会抛出空指针异常(NullPointerException
,简称NPE)。包括以下情况:
- 调用一个
null
对象实例的方法 - 访问或修饰
null
对象的字段 - 获取数组为
null
时的长度 - 访问或修饰数组为
null
时的索引值 - 抛出
Throwable
对象为null
时的异常
虽然代码很难万无一失地避免所有NPE,但是也要尽量减少。所以一些防御性的编程技巧,可以将NPE控制在一个很好的水平上。
空指针案例
1. 调用业务方法的返回值对象
在不清楚一个方法的返回值是否存在返回null
的情况,直接使用对象返回值。
People people = new People();
People user = people.getUser("name");
String name = user.getName();
System.out.println(name);
上面示例中的
people.getUser("name");
调用返回的对象不清楚是否为null
,后面直接调用该对象的方法造成NPE。
2. 包装类自动拆箱的值
在包装类对象的值为null
的情况下,进行自动拆箱操作。
Integer a = null;
int b = a;// System.out.println(1 == a);
上面示例中包装类对象
a
定义时的初始化值为null
,在将a
赋值给基本数据类型的b
的时候,以及与基本数据类型1
进行相等逻辑操作的时候,都进行了自动拆箱操作,a
为null
时造成NPE。
3. 集合和数组空对象的遍历
在不清楚集合或数组是否为null
的时候,对它们进行遍历操作。
List<String> list = null;// String[] list = null;
for (String string : list) {
System.out.println(string);
}
在方法返回或者自己定义的数组和集合,只要有
null
的情况(不包括数组和集合长度为0的情况),进行遍历操作时造成NPE。
4. Spring没注入实例的使用
在使用Spring框架时,如果注入对象实例失败,此时该对象也是null
。
public class BeanExample {
@Autowired
private BeanProvider beanProvider;
public void run() {
this.beanProvider.sayHello(this.name, this.age);
}
}
当因为操作不当导致
beanProvider
没有注入,在调用sayHello()
方法的时候造成NPE。
5. ConcurrentHashMap和Hashtable的值
对某些不支持null
值的集合添加null
值元素,比如ConcurrentHashMap
和Hashtable
。
ConcurrentHashMap<String, String> map = new ConcurrentHashMap();
map.put("a", null);
Hashtable<String, String> hashtable = newHashtable<>();
hashtable.put("a", null);
这些集合的底层
put(K key,V value)
方法中,在key
或者value
为null
的情况下会造成NPE。
二、怎样防止空指针异常
既然NPE难以避免,我们就要去找各种方法来解决。既要有良好的编码习惯,也要细心的去把控业务。
1. 普通处理
在针对调用业务方法进行NPE普通地防御,可以简单的添加非空判断。
People people = new People();
People user = people.getUser("name");
if (user != null) {
String name = user.getName();
System.out.println(name);
}
2. 定义对象时的初始化
在自己定义对象的时候,注意初始化的值可不可以为null
。
// String str = "";
// 初始化为空字符串People people = newPeople();
// 初始化为对象
People user = people.getUser("name");
3. 使用 equals() 方法注意
已知非空对象为调用方,比如将常量值、枚举值作为调用方,避免使用未知对象去调用方法,可有效避免NPE。
String str = "123", string = null;
System.out.println(str.equals(string));
4. 使用 valueOf() 代替 toString() 方法
使用toString()
方法要利用对象去调用方法,而对象在不清楚是否为null
的情况下,会抛出NPE。使用valueOf()
方法可以避免使用未知对象去调用方法来避免。
People people = null;
System.out.println(String.valueOf(people)); // print:null
System.out.println(people.toString()); // NPE
5. 使用开源库非空判断方法
推荐使用各大开源库的StringUtils
字符串和CollectionUtils
集合等工具进行非空判断。
String str = null;
List<String> list = null;
if (!StringUtils.isEmpty(str)) {
System.out.println(str);
}
if (!CollectionUtils.isEmpty(list)) {
System.out.println(list);
}
6. 方法返回空集合或空数组
在方法中返回空数组和空集合而不是返回null
,JDK自带的Collections
集合工具类提供了多种空集合的定义。
public People[] getUsersArr() {
return new People[]{};
}
public List<People> getUsers() {
// return Collections.emptyMap();
// return Collections.emptySet();
return Collections.emptyList();
}
7. 定义数据库字段是否为空
在一些特定字段根据业务确定是否可为空,以及合理设置默认值。比如:表示业务状态的字段。
CREATE TABLE user{ ... status NOT NULL DEFAULT 0 ...}
8. 使用JDK1.8的Optional类
在JDK1.8后提供了防止NPE特定的容器,后面会讲到。
三、Optional
Optional
是一个可以包含null
或者非null
的容器对象。根据源码分析方法功能:
1. 定义方法
1.1 empty
返回一个空的Optaional
实例,在这个实例中没有值存在。
public static<T> Optional<T> empty() {
@SuppressWarnings("unchecked")
Optional<T> t = (Optional<T>) EMPTY;
return t;
}
1.2 of
返回一个值不能为空的Optional
实例,在这个实例中值为null
时抛出NPE。
public static <T> Optional<T> of(T value) {
return new Optional<>(value);
}
private Optional(T value) {
this.value = Objects.requireNonNull(value);
}
1.3 ofNullable
返回一个值可以为空的Optional
实例,在这个实例中值为null
时返回一个空的Optaional
实例。
public static <T> Optional<T> ofNullable(T value) {
return value == null ? empty() : of(value);
}
2. 功能方法
2.1 isPresent
如果有值存在,返回true
,否则返回false
。
People people = new People();
System.out.println(Optional.ofNullable(people).isPresent());// print: true
people = null;
System.out.println(Optional.ofNullable(people).isPresent());// print: false
2.2 get()
如果有值存在,返回值,否则抛出NoSuchElementException
。
People people = new People();
System.out.println(Optional.ofNullable(people).get());// print: People@61bbe9ba
people = null;
System.out.println(Optional.ofNullable(people).get());// print: Exception in thread "main" java.util.NoSuchElementException: No value present
尽量不要使用该方法获取对象。
2.3 orElse
如果有值存在,返回值,否则返回该 orElse
方法的参数,可以用来定义默认值。
String str = null;
String result = Optional.ofNullable(str).orElse("default");//print:default
System.out.println(result);
2.4 orElseGet
如果有值存在,返回值,否则返回提供者函数,可以用函数返回值来定义默认值。
String str = null;
String result = Optional.ofNullable(str).orElseGet(() -> "ajn");//print:ajn
System.out.println(result);
2.5 orElseThrow
如果有值存在,返回值,否则返回函数接口参数提供的异常。
String str = null;
String result = Optional.ofNullable(str).orElseThrow(IllegalArgumentException::new);// print: Exception in thread "main" java.lang.IllegalArgumentException
System.out.println(result);
关于更多函数接口的内容,关注Java函数式编程
2.6 ifPresent
如果有值存在,方法参数提供的函数接口会进行处理,否则不做任何操作。
Optional.ofNullable(getPeople()).ifPresent(people -> {
System.out.println("the people is nut null: " + people);
});
上面代码等价于:
People people = getPeople();
if (people != null) {
System.out.println("the people is nut null: " + people);
}
2.7 filter
如果有值存在,并且值符合给定的函数条件,返回当前Optional
,否则返回一个空的Optaional
实例,可以用来过滤特殊值。
String name = "AiJiangnan";// 给定的条件是字符串包含Ai
String result = Optional.of(name).filter(str -> str.contains("Ai")).orElse("字符串不包含Ai");
System.out.println(result);
2.8 map
如果有值存在,可以将该值的类型转换成其他类型,并返回转换后类型的Optional
实例,否则返回一个空的Optaional
实例,可以链式判空,非常实用。
People people = null;
String result = Optional.ofNullable(people)
.map(People::getName)
.map(String::toUpperCase)
.orElse("default");
System.out.println(result);
只有当
people
对象不为null
,并且people.getName()
不为null
,才返回name全部转换为大写的字符串,否则都返回 default。
2.9 flatMap
如果有值存在,可以将该值的类型转换成其他类型,但最终只能转成 Optional
实例,否则返回一个空的Optaional
实例。该方法与map
方法类似,只是该方法返回的Optional
实例由函数参数返回。
People people = new People();
people.setName(" ajn ");
String result = Optional.ofNullable(people)
.flatMap(peo -> Optional.ofNullable(peo.getName()))
.flatMap(str -> Optional.of(str.toUpperCase()))
.orElse("default");
System.out.println(result);
空指针异常与Optional类的更多相关文章
- Java8新特性——Optional类的使用(有效的避免空指针异常)
OPtional类的使用 概述 到目前为止,臭名昭著的空指针异常是导致Java应用程序失败的最常见原因.以前,为了解决空指针异常,Google公司著名的Guava项目引入了Optional类,Guav ...
- Java 8 Optional类使用的实践经验
前言 Java中空指针异常(NPE)一直是令开发者头疼的问题.Java 8引入了一个新的Optional类,使用该类可以尽可能地防止出现空指针异常. Optional 类是一个可以为null的容器对象 ...
- Java8 新特性 Optional 类
Optional 类的简介 Optional类的是来自谷歌Guava的启发,然后就加入到Java8新特性中去了.Optional类主要就是为子决解价值亿万的错误,空指针异常. Optional ...
- 【Java8新特性】不了解Optional类,简历上别说你懂Java8!!
写在前面 最近,很多读者出去面试都在Java8上栽了跟头,事后自己分析,确实对Java8的新特性一知半解.然而,却在简历显眼的技能部分写着:熟练掌握Java8的各种新特性,能够迅速使用Java8开发高 ...
- Java8新特性之空指针异常的克星Optional类
Java8新特性系列我们已经介绍了Stream.Lambda表达式.DateTime日期时间处理,最后以"NullPointerException" 的克星Optional类的讲解 ...
- 【Java8新特性】Optional类在处理空值判断场景的应用 回避空指针异常 编写健壮的应用程序
一.序言 空值异常是应用运行时常见的异常,传统方式为了编写健壮的应用,常常使用多层嵌套逻辑判断回避空指针异常.Java8新特性之Optional为此类问题提供了优雅的解决方式. 广大程序员朋友对空值异 ...
- (八)jdk8学习心得之Optional类
八.Optional 类 1. 作用:可以存放空指针null,主要用于解决空指针问题. 2. 使用方法 1) 创建对象(2种方法) Optional optional = Optional.of(非n ...
- Java 8 Optional 类
转自:https://www.runoob.com/java/java8-optional-class.html Optional 类是一个可以为null的容器对象.如果值存在则isPresent() ...
- Java8 Optional类
概述 到目前为止,著名的NullPointerException是导致Java应用程序失败的最常见原因.过去,为了解决空指针异常,Google公司著名的Guava项目引入了Optional类,Guav ...
随机推荐
- ubuntu系统定时运行 crontab
1,crontab是个啥? ubuntu系统自带cron工具,cron是一个系统上的定时工具,用它的好处在于,不同的程序可以用同一个计时器,这样就省得不同程序各自sleep了,另外它还支持比较多的个性 ...
- Android Studio3.0.0之前首次安装通用配置
一.第一次安装: 温馨提示:在安装Android Studio之前,建议先提前准备好单独的Android SDK,这个可以在AndroidDevTools网站下载.以前用Eclipse做过Androi ...
- shiro认证和授权
一.shiro基础概念 Authentication:身份认证 / 登录,验证用户是不是拥有相应的身份: Authorization:授权,即权限验证,验证某个已认证的用户是否拥有某个权限:即判断用户 ...
- navicat操作mysql数据库
1.利用mysql来做ER图 1.1点击模型->新建模型->点击表->新建表,这样就可以了 1.2 建好的ER图->工具 有导出到sql ,有同步到数据库 1.3 建好的表,可 ...
- oracle 锁表处理
1.查询 select object_name,machine,s.sid,s.serial#from v$locked_object l,dba_objects o ,v$session swher ...
- 利用python装饰器为字符串添加,HTML标签
# 为字符串添加HTML标签 import time def zhuang(fun): def zhaung_1(*args, **kargs): # time.sleep(1) html_str = ...
- SSH多表操作入门
这个系统写到这里,所涉及到的都是单表的操作,增删改查,现在功能需要完善,涉及到多表操作,开始是毫无头绪,书上的代码也没有现成的可以借鉴,想来就从最简单的开始.问题出现了很多,不过最后在龙哥的提示下还是 ...
- CI框架Email类发送邮件提示Unable to send data: . The following SMTP error was encountered: Unable to .......
最近服务器迁移,然后CI框架做的项目发邮件全挂掉了,刚开始是25端口没开,然后开了正好还是有问题, 1.打印请求信息和返回信息 echo $this->email->print_debug ...
- 【转】Git常用命令指南
1.git init 初始化一个Git仓库,git init –bare example.git创建一个裸仓,即没有工作区的git仓库.2.添加文件到Git仓库,分两步:git add <fil ...
- python之文件复制
python文件复制操作. # -*- coding: utf-8 -*- import shutil import os # file_path = 'C:\\Users\\WT\\Desktop\ ...