以前对NULL的处理
//String userName = "张三"; String userName = null; if(userName != null){ System.out.println("字符串的长度:" + userName.length()); }else{ System.out.println("字符串为空"); }
Optional类
Optional是一个没有子类的工具类,Optional是一个可以为null的容器对象,它的主要作用就是为了避
免Null检查,防止NullpointerException
Optional的基本使用
// 第一种方式 通过of方法 of方法是不支持null的 Optional<String> op1 = Optional.of("zhangsan"); //Optional<Object> op2 = Optional.of(null); // 第二种方式通过 ofNullable方法 支持null Optional<String> op3 = Optional.ofNullable("lisi"); Optional<Object> op4 = Optional.ofNullable(null); // 第三种方式 通过empty方法直接创建一个空的Optional对象 Optional<Object> op5 = Optional.empty();
Optional的常用方法
/** * Optional中的常用方法介绍 * get(): 如果Optional有值则返回,否则抛出NoSuchElementException异常 * get()通常和isPresent方法一块使用 * isPresent():判断是否包含值,包含值返回true,不包含值返回false * orElse(T t):如果调用对象包含值,就返回该值,否则返回t * orElseGet(Supplier s):如果调用对象包含值,就返回该值,否则返回 Lambda表达式的返 回值 */ Optional<String> op1 = Optional.of("zhangsan"); Optional<String> op2 = Optional.empty(); // 获取Optional中的值 if(op1.isPresent()){ String s1 = op1.get(); System.out.println("用户名称:" +s1); } if(op2.isPresent()){ System.out.println(op2.get()); }else{ System.out.println("op2是一个空Optional对象"); } String s3 = op1.orElse("李四"); System.out.println(s3); String s4 = op2.orElse("王五"); System.out.println(s4); String s5 = op2.orElseGet(()->{ return "Hello"; }); System.out.println(s5); Person p = new Person("zhangsan",18); Optional<Person> op = Optional.of(p); String name = getNameForOptional(op); System.out.println("name="+name); public String getNameForOptional(Optional<Person> op){ if(op.isPresent()){ String msg = //op.map(p -> p.getName()) op.map(Person::getName) //.map(p -> p.toUpperCase()) .map(String::toUpperCase) .orElse("空值"); return msg; } return null; }
额外补充三个常用的:
获取Optional容器的对象:
T orElseThrow(Supplier<? extends X> exceptionSupplier)
:如果有值则将其返回,否则抛出由Supplier接口实现提供的异常。
过滤:
Optional<T> filter(Predicate<? super <T> predicate)
:如果值存在,并且这个值匹配给定的 predicate,返回一个Optional用以描述这个值,否则返回一个空的Optional。
映射
<U>Optional<U> map(Function<? super T,? extends U> mapper)
:如果有值,则对其执行调用映射函数得到返回值。如果返回值不为 null,则创建包含映射返回值的Optional作为map方法返回值,否则返回空Optional。
Optional实战
这部分是通过查阅实际上开发中写法总结出来的,并不是只介绍了Optional的概念,而是融入了实际开发中考虑到的情况,实际上在开发中空指针异常的异常很常见,而灵活的的使用Optional能够很好的避免这种情况。
场景一:
PatientInfo patientInfo = patientInfoDao.getPatientInfoById(consultOrder.getPatientId()); if (patientInfo != null) { consultInfoResp.setPatientHead(patientInfo.getHead()); } // 使用Optional 和函数式编程,一行搞定,而且像说话一样 Optional.ofNullable(patientInfo).ifPresent(p -> consultInfoResp.setPatientHead(p.getHead()));
场景二:
public void test1() throws Exception { Student student = new Student(null, 3); if (student == null || isEmpty(student.getName())) { throw new Exception(); } String name = student.getName(); // 业务省略... // 使用Optional改造 Optional.ofNullable(student).filter(s -> !isEmpty(s.getName())).orElseThrow(() -> new Exception()); } public static boolean isEmpty(CharSequence str) { return str == null || str.length() == 0; }
场景三:
public static String getChampionName(Competition comp) throws IllegalArgumentException { if (comp != null) { CompResult result = comp.getResult(); if (result != null) { User champion = result.getChampion(); if (champion != null) { return champion.getName(); } } } throw new IllegalArgumentException("The value of param comp isn't available."); }
这个在开发中是很常见的一种逻辑。去判读传进来的参数时候为空,或者是从数据库中获取的对象。由于某些原因,我们不能很流程的直接这样写。
comp.getResult().getChampion().getName()
上面的写法用Optional改写:
public static String getChampionName(Competition comp) throws IllegalArgumentException { return Optional.ofNullable(comp) .map(Competition::getResult) // 相当于c -> c.getResult(),下同 .map(CompResult::getChampion) .map(User::getName) .orElseThrow(()->new IllegalArgumentException("The value of param comp isn't available.")); }
场景四:
int timeout = Optional.ofNullable(redisProperties.getTimeout()) .map(x -> Long.valueOf(x.toMillis()).intValue()) .orElse(10000);