商城网站制作深圳网站制作,做自媒体可以参考的外国网站,做pos机网站有必要么,医疗器械网站建设策划书文章目录 一、Optional概述1、烦人的NullPointerException2、Optional简介 二、Optional使用1、创建Optional对象2、isPresent()与ifPresent()应用源码解析3、get()应用源码解析4、orElseThrow()应用源码解析5、map()应用源码解析6、flatMap()应用源码… 文章目录 一、Optional概述1、烦人的NullPointerException2、Optional简介 二、Optional使用1、创建Optional对象2、isPresent()与ifPresent()应用源码解析3、get()应用源码解析4、orElseThrow()应用源码解析5、map()应用源码解析6、flatMap()应用源码解析7、filter()应用源码解析8、orElse()应用源码解析9、orElseGet()应用源码解析10、orElseThrow()应用源码分析 一、Optional概述
1、烦人的NullPointerException
在日常开发中NullPointerException相信所有人都见过不管你是刚入行的萌新还是骨灰级玩家对于它都是耳熟能详的。它的出现可以说无处不在总是能在各种场景下出现。那么对于如何防止它的出现我们平时都是被动的采用各种非空校验但是它还是经常能出现在我们的视线中。
public String getCompanyName(Student student){if (student ! null){Job job student.getJob();if (job ! null){Company company job.getCompany();if (company ! null){String name company.getName();return name;}else {return no company;}}else {return no job;}}else {return no student;}
}对于上述这段代码相信大家平时工作类似的代码经常会有出现。每一次在获取到一个对象时都进行一个null的判断然后才继续后续的实现。但是这种方式很不好首先会存在大量的if-else判断嵌套导致代码的可读性和扩展性极差。此时有的同学可能就会使用卫语句这么改造如下所示
public String getCompanyName(Student student){if (student null){return no student;}Job job student.getJob();if (job null){return no job;}Company company job.getCompany();if (company null){return no company;}return company.getName();
}这种判断已经有意识的避免了大量嵌套判断但是同样存在多个不同的判断点代码维护同样困难。
2、Optional简介
为了防止空指针异常的出现Java8中引入了一个新类Optional对于它之前我们已经进行了简单的实现。其本质就是通过Optional类对值进行封装 当有值的时候会把该值封装到Optional类中。如果没有值的话则会在该类封装一个Empty。
二、Optional使用
在Optional类中基于函数式接口提供了一些用于操作值的方法。
1、创建Optional对象
创建Optional该类提供了三种方法操作分别为empty()、of()、ofNullable()。使用方式如下所示
OptionalStudent studentOptional Optional.empty();
OptionalStudent studentOptional Optional.of(student);
OptionalStudent studentOptional Optional.ofNullable(student);这三者有什么区别根据源码分析如下
// 源码分析
public staticT OptionalT empty() {SuppressWarnings(unchecked)OptionalT t (OptionalT) EMPTY; // private static final Optional? EMPTY new Optional();return t;
}
public static T OptionalT of(T value) {return new Optional(value);
}private Optional(T value) {this.value Objects.requireNonNull(value);
}public static T T requireNonNull(T obj) {if (obj null)throw new NullPointerException();return obj;
}
public static T OptionalT ofNullable(T value) {return value null ? empty() : of(value);
}根据源码可知empty()会直接返回一个空的Optional实例内部不会存在任何值。
of()会返回一个存在值的Optional对象并且该值不允许null的存在。如果调用该方法时传入参数是null则立刻抛出NullPointerException而不是等到你用这个对象时才抛出相当于进行了立即检查。
ofNullable()同样也会返回一个存在值的Optional对象但是它和of()最大的不同在于它会对传入的值进行判断如果传入的值为null其会调用empty()返回一个不包含内容的Optional如果不为null则会调用of()返回一个包含内容的Optional。
2、isPresent()与ifPresent()应用源码解析
Optional类中提供了两个方法用于判断Optional是否有值分别是isPresent()和ifPresent(Consumer? super T consumer)。其一般与ofNullable()搭配使用因为of()在创建时已经完成了判断而empty()只是单纯了实例化了一个Optional对象。
// 使用实例
public class PresentDemo {public static void getStudentName(Student student){OptionalStudent optional Optional.ofNullable(student);if (optional.isPresent()){//student不为nullStudent student1 optional.get();System.out.println(student1);}else {System.out.println(student为null);}optional.ifPresent(s- System.out.println(s));}public static void main(String[] args) {Student student new Student(1,zhangsan,M);getStudentName(student);}
}// 源码分析
// isPresent()内部非常简单就是判断这个值是否为null。
public boolean isPresent() {return value ! null;
}public void ifPresent(Consumer? super T consumer) {if (value ! null)consumer.accept(value);
}ifPresent()方法在执行时接收一个consumer函数式接口如果value不为null则通过consumer中的accept方法获取该值。
3、get()应用源码解析
get()的使用非常简单但不安全因为其在获取值的时候如果值存在则直接返回封装在Optional中的值如果不存在则抛出NoSuchElementException。因此它的使用前提是已经确定Optional中有值否则没有使用意义。
// 使用实例
OptionalStudent studentOptional Optional.ofNullable(student);
if (studentOptional.isPresent()){Student result studentOptional.get();
}// 源码分析
public Tget() {if (value null) {throw new NoSuchElementException(No value present);}return value;
}4、orElseThrow()应用源码解析
该方法与get()类似都是用于取值但是当Optional中没有值时get()会直接抛出NoSuchElementException这样的话就存在了一定的局限性因为有时可能需要抛出自定义异常。此时就可以使用orElseThrow()它在取值时如果Optional中没有值时可以抛出自定义异常。
// 使用实例
OptionalStudent optional Optional.ofNullable(student);try {// null 就抛异常Student result optional.orElseThrow(MyException::new);System.out.println(result);
} catch (MyException e) {e.printStackTrace();
}// 源码分析
public X extends Throwable T orElseThrow(Supplier? extends X exceptionSupplier) throws X {if (value ! null) {return value;} else { // null 的话就抛异常throw exceptionSupplier.get();}
}5、map()应用源码解析
map()可以实现类型转换与JDK8的Stream的map类似只不过一个是转换Stream的泛型一个是转换Optional的泛型。
// 使用案例
if (studentOptional.isPresent()){// Student类型转为String类型OptionalString nameOptional studentOptional.map(Student::getName);
}// 源码分析
publicU OptionalU map(Function? super T, ? extends U mapper) {Objects.requireNonNull(mapper);if (!isPresent())return empty();else {return Optional.ofNullable(mapper.apply(value));}
}6、flatMap()应用源码解析
刚才已经通过map()获取了学生的姓名操作非常简单。但是当产生链路获取时map可以使用么 如学生-工作-公司-公司名称。
现在可能大家脑袋里已经有了一个想法就是通过map()代码结构如下
studentOptional.map(Student::getJob).map(Job::getCompany).map(Company::getName);但是这段代码是无法通过编译的。因为根据map的学习每一次在调用的时候都会对Optional的泛型进行改变最终产生多层Optional嵌套的结构。
对于这个问题的解决Optional类中提供了另外一个获取值的方法flatMap()。它本身用于多层调用同时对于结果它不会形成多个Optional而是将结果处理成最终的一个类型的Optional。但是通过flatMap获取的返回值必须是Optional类型。而map则没有这个限制。
// 使用实例
OptionalString nameOptional studentOptional.flatMap(Student::getJob).flatMap(Job::getCompany).map(Company::getName);// 源码分析
publicU OptionalU flatMap(Function? super T, OptionalU mapper) {Objects.requireNonNull(mapper);if (!isPresent())return empty();else {// 多次调用不会生成Optional嵌套return Objects.requireNonNull(mapper.apply(value));}
}7、filter()应用源码解析
Optional类中提供了数据过滤的方法filter()来实现这个需求。其会根据传入的条件进行判断如果匹配则返回一个Optional对象并包含对应的值否则返回一个空值的Optional。
// 使用实例
OptionalCompany company companyOptional.filter(c - bank.equals(c.getName()));源码是传入一个Predicate如果不为null的话就会调用predicate的test方法做判断。
// 源码分析
public OptionalT filter(Predicate? super T predicate) {Objects.requireNonNull(predicate);if (!isPresent())return this;elsereturn predicate.test(value) ? this : empty();
}8、orElse()应用源码解析
在取值的时候如果值不存在有时我们会考虑返回一个默认值。该需求就可以通过orElse()实现。
其内部会判断值是否为null如果不为null则返回该值如果为null则返回传入的默认值。
// 使用案例
String value studentOptional.flatMap(Student::getJob).flatMap(Job::getCompany).map(Company::getName).orElse(default value);// 源码分析
publicT orElse(T other) {// null的话取默认值return value ! null ? value : other;
}9、orElseGet()应用源码解析
orElseGet()也是用于当Optional中没有值时返回默认值的方法。但是它与orElse()的区别在于它是延迟加载的。只有当Optional中没有值是才会被调用。
// 源码分析
public T orElseGet(Supplier? extends T other) {return value ! null ? value : other.get();
}// 代码案例
System.out.println(Optional.ofNullable(student).orElse(getStr(a)));
System.out.println(Optional.ofNullable(null).orElse(getStr(b)));
System.out.println(Optional.ofNullable(student).orElseGet(() -getStr(a)));
System.out.println(Optional.ofNullable(null).orElseGet(() -getStr(b)));我们发现 当数据不为null的时候orElseGet不会执行。
所以在使用时更加推荐使用orElseGet()因为它使用延迟调用所以性能更加优异。
10、orElseThrow()应用源码分析
orElseThrow很简单如果为null的话就抛一个异常。
// 源码分析
public X extends Throwable T orElseThrow(Supplier? extends X exceptionSupplier) throws X {if (value ! null) {return value;} else {throw exceptionSupplier.get();}
}