程序中常常须要对null状况进行处理,好比Course类中有一个List
如今想要查看某个student的name属性的长度,不负责任(不处理null)的写法以下:
Course course = new Course("数学"); Student s0 = new Student("s0"); Student s1 = new Student(null); Student s2 = null; course.addStudent(s0, s1, s2); int index = 1; String name = course.getStuList().get(index).getName(); //index = 1或2都会抛出NullPointerException System.out.println(name.length());
String name = course.getStuList().get(index).getName()
这样写当然省事,可是当s2为null或者s1对象的name为null时,都会抛出你们熟悉的NullPointerException。
因此须要使用大量的if...else语句对变量否为null进行判断。java
int index = 1; Student student = course.getStuList().get(index); String errorMessage = "处理过程当中无null"; String name = ""; if(student!=null) { name = student.getName(); if(name!=null) { System.out.println(name.length()); }else { errorMessage="student对象的name为null"; } }else { errorMessage="student对象为null"; } sysout System.out.println(errorMessage);
null是一个特殊值,并非一个类型,student.getName()
可能返回null也可能返回String类型对象,这是两种不一样的状况。
Java 8中引入了Optional类型来统一处理null与对应的类型。该类型为容器类型,能够包含某个类型的非空值与空值,因此能够对他们统一处理。
Optional基本用法以下:api
Optional<Student> stuNullable = Optional.empty();//表明null的Optional对象 Student stu = new Student("s0"); System.out.println(stuNullable.isPresent());//false,判断里面是否存在Student对象 //Student student = stuNullable.get();//将抛出NoSuchElementException Optional<Student> stuNotNull = Optional.ofNullable(stu); //表明非空的Student,实际上将stu对象放入该Optional容器中 System.out.println(stuNotNull.isPresent());//true Student student = stuNotNull.get(); //返回刚才装入的stu对象
其中Optional.ofNullable(stu)
的做用是:当stu为null时,返回Optional.empty(),不然返回包含stu对象的Optional对象(即,Optional.of(stu))。
到如今为止咱们可使用Optional来代替前面的对null值的直接处理,代码以下:数组
Course course = new Course("数学"); Student s0 = new Student("s0"); Student s1 = new Student(null); Student s2 = null; course.addStudent(s0, s1, s2); int index = 1; Student student = course.getStuList().get(index); Optional<Student> stu = Optional.ofNullable(student);//将student放入Optioanl中进行处理 String errorMessage = "处理过程当中无null"; String name = ""; if (stu.isPresent()) { Optional<String> nameOfNullable = Optional.ofNullable(stu.get().getName()); if (nameOfNullable.isPresent()) { name = nameOfNullable.get(); System.out.println(name.length()); }else { errorMessage="student对象的name为null"; } }else { errorMessage="student对象为null"; } System.out.println(errorMessage);
呃.....代码更复杂了。但至少让你不能忽略null值了。
再看看Optional中的其余方法ifPresent
与orElse
oracle
stu.ifPresent(e->System.out.println(e.getName()));//若是存在对象,则Optional中的包含的对象getName返回的值 Student defaultStudent = new Student("默认对象"); Student orElse = stu.orElse(defaultStudent); //若是存在对象直接返回该对象,不然返回defaultStudent对象
彷佛无补于事。ide
对上面的代码可使用map方法进行改造,以下所示:测试
int index = 0; String errorMessage = "处理过程有null"; String name = ""; Optional<Course> courseNullable = Optional.ofNullable(course); Optional<String> resultOptional = courseNullable.map(e->e.getStu(index)).map(e->e.getName()); String result = resultOptional.orElse(errorMessage);//resultOptional中可能为null,也可能有值。若是未null,则返回errorMessage。 System.out.println(result);
map方法入参为Function类型(能够将Optional中原来的类型转换成新的类型)。
map(e->e.getStu(index))
就是将Courset类型转换成Student类型
map(e->e.getName())
则是将Student类型转换成String类型。
map方法返回值为Optional类型,因此能够以链式风格map(e->e.getStu(index)).map(e->e.getName())
取代上面复杂的if...else处理。this
这个例子体现出了Optional的优越性,便可以经过其优雅的处理null值。
窃觉得,相比较Optioanl带来的优越性,其语法仍是有点复杂。建议先掌握其语法,这样至少看别人的相关代码的时候不会无所适从。code
class Student { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } public Student(String name) { this.name = name; } @Override public String toString() { return "Student [name=" + name + "]"; } } class Course {// 课程 private String name; private List<Student> stuList; public String getName() { return name; } public void setName(String name) { this.name = name; } public void addStudent(Student... stus) { for (Student student : stus) { stuList.add(student); } } public Student getStu(int i) { return stuList.get(i); } public List<Student> getStuList() { return stuList; } public Course(String name) { this.name = name; stuList = new ArrayList<>(); } }
查看jdk文档,Optional的说明以下:htm
Optional is primarily intended for use as a method return type where there is a clear need to represent "no result," and where using null is likely to cause errors.
即,Optional主要用于修饰方法的返回类型,来表示“没有结果”这个返回结果,还用在使用null做为返回类型容易致使出错的地方。
那么,我么可使用Optional来改造Course的Student getStu(int i)
代码:
public Student getStu(int i) { return stuList.get(i); }
该段代码主要有两个问题:
改造后代码以下:
public Optional<Student> getStu(int i) { if (i >= stuList.size()) return Optional.empty(); // 带表明null的Optional实例 Student student = stuList.get(i); if (student == null) return Optional.empty(); return Optional.of(student); }
或者进一步简化,改形成这样:
public Optional<Student> getStu(int i) { if (i >= stuList.size()) return Optional.empty(); Student student = stuList.get(i); return Optional.ofNullable(student); }
Optional.ofNullable方法能够处理入参为null的状况。其相关文档描述以下
Returns an Optional describing the specified value, if non-null, otherwise returns an empty Optional.
定义测试方法以下
private static void getStuByIndex(Course course, int index) { Student stu0 = course.getStu(index).orElse(new Student("默认学生"));//若是为null,则返回“默认学生”对象 System.out.println(stu0); }
测试代码以下:
Course course = new Course("数学"); Student s0 = new Student("s0"); Student s1 = new Student(null); Student s2 = null; course.addStudent(s0, s1, s2); getStuByIndex(course, 0); getStuByIndex(course, 1); getStuByIndex(course, 2);//s2为null getStuByIndex(course, 3);//越界,返回Optional.empty()
输出:
Student [name=s0] Student [name=null] Student [name=默认学生] Student [name=默认学生]
测试flatmap代码以下
Optional<Course> courseNullable = Optional.ofNullable(course); Optional<String> r0 = courseNullable.flatMap(e->e.getStu(0)).map(Student::getName); Optional<String> r1 = courseNullable.flatMap(e->e.getStu(1)).map(Student::getName); Optional<String> r2 = courseNullable.flatMap(e->e.getStu(2)).map(Student::getName); Optional<String> r3 = courseNullable.flatMap(e->e.getStu(3)).map(Student::getName); System.out.println(r0); System.out.println(r1);//Student的name属性为null,返回Optional.empty() System.out.println(r2);//Student为null,返回Optional.empty() System.out.println(r3);//数组越界,返回Optional.empty()
输出以下:
Optional[s0] Optional.empty Optional.empty Optional.empty
对比之前的代码
Optional<String> resultOptional = courseNullable.map(e->e.getStu(index)).map(e->e.getName());
将map(e->e.getStu(0))
改为了flatMap(e->e.getStu(0))
。这是由于改造前的e->e.getStu(0)
返回的是Student对象,
而改造后返回的是Optional<Student>
类型对象。观察改造后的代码段:
Optional<Optional<Student>> xa = courseNullable.map(e->e.getStu(2)); Optional<Student> xb = courseNullable.flatMap(e->e.getStu(2));
能够看到xa并非咱们想要的结果,而xb才是咱们想要的结果。前面已经提到Optional
至关于一个容器,那么Optional<Optional<Student>>
至关于容器中嵌套一个容器,在这里咱们须要关注的是大容器里面的Optional<Student>
类型对象。flatMap中的flat能够理解为平坦化,至关于 从嵌套的容器中取出本身真正想要的元素。