在Java开发的过程中,经常会遇到烦人的
NullPointerException
异常,为了避免NullPointerException
,遇到逐层解析的场景,需要嵌套多层if else
进行解析。
示例代码如下:
SchoolInfo.java
/**
* 学校信息 SchoolInfo.java
*/
public class SchoolInfo {
/**
* 编码
*/
private String code;
/**
* 学校名称
*/
private String name;
public String getCode() {
return code;
}
public SchoolInfo setCode(String code) {
this.code = code;
return this;
}
public String getName() {
return name;
}
public SchoolInfo setName(String name) {
this.name = name;
return this;
}
}
ClassInfo.java
/**
* 班级信息 ClassInfo.java
*/
public class ClassInfo {
/**
* 编码
*/
private String code;
/**
* 班级名称
*/
private String name;
/**
* 班主任
*/
private String teacherName;
/**
* 所属学校信息
*/
private SchoolInfo schoolInfo;
public String getCode() {
return code;
}
public ClassInfo setCode(String code) {
this.code = code;
return this;
}
public String getName() {
return name;
}
public ClassInfo setName(String name) {
this.name = name;
return this;
}
public String getTeacherName() {
return teacherName;
}
public ClassInfo setTeacherName(String teacherName) {
this.teacherName = teacherName;
return this;
}
public SchoolInfo getSchoolInfo() {
return schoolInfo;
}
public ClassInfo setSchoolInfo(SchoolInfo schoolInfo) {
this.schoolInfo = schoolInfo;
return this;
}
}
StudentInfo.java
/**
* 学生信息 StudentInfo.java
*/
public class StudentInfo {
/**
* 编码
*/
private String code;
/**
* 姓名
*/
private String name;
/**
* 性别
*/
private String gender;
/**
* 所属班级信息
*/
private ClassInfo classInfo;
public String getCode() {
return code;
}
public StudentInfo setCode(String code) {
this.code = code;
return this;
}
public String getName() {
return name;
}
public StudentInfo setName(String name) {
this.name = name;
return this;
}
public String getGender() {
return gender;
}
public StudentInfo setGender(String gender) {
this.gender = gender;
return this;
}
public ClassInfo getClassInfo() {
return classInfo;
}
public StudentInfo setClassInfo(ClassInfo classInfo) {
this.classInfo = classInfo;
return this;
}
}
开发过程中经常遇到的一个场景是:需要获取学生StudentInfo
的所属学校名称School::name
。在Java 7及以下版本中,我们会不得不采用以下方法进行操作:
public class TestStudent {
public static void main(String[] args) {
// 学校信息
SchoolInfo schoolInfo = new SchoolInfo().setCode("HZXH07").setName("杭州测试学校");
// 班级信息
ClassInfo classInfo = new ClassInfo().setCode("0203").setName("高二(3)班").setSchoolInfo(schoolInfo);
// 学生信息
StudentInfo studentInfo = new StudentInfo().setCode("2302010").setName("Jack").setGender("Male").setClassInfo(classInfo);
String schoolName = TestStudent.getSchoolName(studentInfo);
System.out.println(schoolName);
}
/**
* 获取学生所属学校名称
*
* @param studentInfo
* @return
*/
private static String getSchoolName(StudentInfo studentInfo) {
String schoolName = "";
// 避免空指针异常,先判断学生信息是否为空
if (studentInfo != null) {
// 再判断所属班级信息是否为空
if (studentInfo.getClassInfo() != null) {
// 再判断班级所属学校信息是否为空
if (studentInfo.getClassInfo().getSchoolInfo() != null) {
schoolName = studentInfo.getClassInfo().getSchoolInfo().getName();
}
}
}
System.out.println(schoolName);
return schoolName;
}
}
上述代码中,为了避免NullPointerException
异常,我们不得不用了三层if
来分别判断studentInfo
、studentInfo.getClassInfo()
、studentInfo.getClassInfo().getSchoolInfo()
是否为null
。但凡有一层为null
,都会中止下一层的判断。
优雅的使用Optional
Optional
是Java8的一个新特性,官方文档对于Optional
的解释如下:
A container object which may or may not contain a non-null value. If a value is present,
isPresent()
will returntrue
andget()
will return the value.
简单翻译一下就是
Optional是一个容器对象,可以包含也可以不包含非null值。如果值提供(非null)调用
isPresent()
方法会返回true
,并且get()
方法会返回该值。
首先贴出简化后的代码:
/**
* 获取学生所属学校名称
*
* @param studentInfo
* @return
*/
private static String getSchoolName(StudentInfo studentInfo) {
String schoolName = Optional.ofNullable(studentInfo).map(student -> student.getClassInfo()).map(class_ -> class_.getSchoolInfo()).map(school -> school.getName()).orElse("");
return schoolName;
}
可以看到,原本的三层if
判断+取值操作,变成了一行的Optional.ofNullable
、.map()
、.orElse()
,从代码量上来说简化不少。当然上面的代码可以进一步简化为:
private static String getSchoolName(StudentInfo studentInfo) {
String schoolName = Optional.ofNullable(studentInfo).map(StudentInfo::getClassInfo).map(ClassInfo::getSchoolInfo).map(SchoolInfo::getName).orElse("");
return schoolName;
}
逻辑上这份代码与上面的代码无多大差异,只是改用了方法引用形式,在这里不展开来讲解。
我们再对Optional.ofNullable
、.map()
、.orElse()
展开来讲解。
Optional.ofNullable
:Returns an Optional describing the specified value, if non-null, otherwise returns an empty Optional.如果非null
,返回一个Optional 对象;否则返回一个空OptionalOptional.map
:If a value is present, apply the provided mapping function to it, and if the result is non-null, return an Optional describing the result. Otherwise return an empty Optional.如果存在值,对其执行提供的映射函数,如果结果非null
,返回结果的Optional 对象;否则返回一个空OptionalOptional.orElse
:Return the value if present, otherwise return other. 如果存在值,则返回;否则返回给定的默认值
把上面的代码加上备注,可能更方便大家理解:
/**
* 获取学生所属学校名称
*
* @param studentInfo
* @return
*/
private static String getSchoolName(StudentInfo studentInfo) {
String schoolName = Optional.ofNullable(studentInfo) // 初始化一个Optional,非空则为studentInfo对象的Optional;反之则为空Optional
.map(StudentInfo::getClassInfo) // 对于非空Optional,执行映射方法StudentInfo::getClassInfo,结果非空则返回结果Optional,反之则返回空Optional
.map(ClassInfo::getSchoolInfo) // 原理同上
.map(SchoolInfo::getName) // 原理同上
.orElse(""); // 上一步Optional为空,则返回默认值"";反之则返回上一步Optional的值
return schoolName;
}
可以看到,原先的三层if
代码,通过Optional
进行优化后,大大减少的代码量,而且从代码的角度来说,看上去也更加的优雅。
以上 : )
扩展阅读: