目录
一、问题与解决方案
Java程序员,对于这种套娃的 if 非空判断,应该是非常熟悉了:
public String getCourse(Student stu) throws Exception {//该方法根据学生获取其课程
if(stu != null){ // 这里必须写非空判断
Teacher t = stu.getTeacher();//获取学生的老师
if(t != null){ // 这里必须写非空判断
return t.getCourse();//返回老师的课程
}
}
return "无课程";
}
看到没,为了获取Student对象的Teacher属性的course属性的值,又要避免NPE(NullPointerException空指针异常的缩写),要写得这么啰嗦。但是如果不这样写,你的代码分分钟报NPE。好在Java 8提供了新的语法来改变这种情况,先看效果:
public String getCourse(Student stu) throws Exception {
return Optional.ofNullable(stu)
.map(s -> s.getTeacher())
.map(t -> t.getCourse())
.orElse("无课程");
}
这是利用Java 8 提供的Optional<T>类,实现对非空等条件的代码简化。另外,这也用到了Java 8函数式编程的语法,所以可以实现链式调用,代码流畅、可读性高。妈妈再也不用担心我写很多 if 套娃了!
二、理解实现的原理
1.初识Java函数式编程
上面用到java.util.Optional<T>类,先来看看Optional<T>这个类的主要方法:
上面方法中的Consumer、Function、Supplier类型的参数,都是Java 8提供的函数式编程的接口,你可以先通俗地理解成就是代码片段。换句话说,从Java 8开始,方法的参数可以不仅是基本类型、对象,也可以是一个代码片段(专业叫法是‘lambda表达式’)。比如基于Java 8遍历一个List集合,在IDEA中会弹出语法提示:
forEach括号中的参数是一个Consumer<...>类型。写成代码就是:
List<Student> stuList= new ArrayList<>();
stuList.forEach(s -> System.out.println(s)); //括号中的 s -> System.out.println(s)就是一个代码片段(表达式)
上面代码括号中的 s -> System.out.println(s) 就是一个代码片段(表达式),看到没,代码片段可以当做参数来传递了。
好了,关于函数式编程的语法特性,点到为止,感兴趣的另外去查阅相关资料,言归正传。
2.Optional<T>的用法
Optional类的作用,就是对于你要操作的对象,包装一层外壳,有了它,代码中如果需要根据对象为null、或不为null,来做不同的事情,就会更方便,也可以更优雅地避免NPE异常。
还记得本文开头那一段 if 套娃的代码吗,改为Optional来实现,可以这样写(先low一点,便于理解):
public static String getCourse(Student stu) throws Exception {
//把要操作的stu包装到Optional对象中,即使stu是null也不会抛空指针异常
Optional<Student> stuOpt = Optional.ofNullable(stu);
//用map方法把s(是stu的别名)对象的teacher属性拿出来,也包装到Optional中,
Optional<Teacher> teaOpt = stuOpt.map(s -> s.getTeacher());
//用map方法把Teacher对象的course属性拿出来,也包装到Optional对象中,
Optional<String> courseOpt = teaOpt.map(t -> t.getCourse());
//返回courseOpt中course属性的值,如果为null就返回“无课程”
return courseOpt.orElse("无课程");
}
如果觉得这样代码太多,那么我们改用链式调用来简化,看看最终的写法:
public String getCourse(Student stu) throws Exception {
return Optional.ofNullable(stu)
.map(s -> s.getTeacher())
.map(t -> t.getCourse())
.orElse("无课程");
}
关注我,一个写了十几年代码还没有秃顶的男人。