
一、是什么
可以理解成是个容器类,是java8诞生的,可以有效的避免空指针异常。
二、API
1、创建Optional
Optional.empty():创建一个空的Optional实例。new Optional<>();Optional.of(T t):创建一个包含t值的Optional实例。若t==null,则get的时候会出现空指针。Optional.ofNullable(T t):是empty和of的结合体,创建一个包含t值的Optional实例。不会出现空指针,若t==null则返回空的Optional实例
2、操作API
isPresent():判断此值是否是null。true:不是null;false:是nullifPresent(Consumer consumer):如果值不是空,则执行consumer代码片段逻辑get():获取此值,若值是null,则会抛出NoSuchElementException("No value present");orElse(T other):若值不是null则返回当前值,否则返回other,有效避免空指针。orElseGet(Supplier s):若值不是null则返回当前值,否则返回s获取的值。有效避免空指针。orElseThrow(Supplier extends X> exceptionSupplier):若值不是null则返回当前值,否则抛出异常。filter(Predicate super T> predicate):根据某种规则进行过滤。map(Function f):如果有值对其处理,并返回处理后的Optional,否则返回Optional.empty()flatMap(Function mapper):与map类似,要求返回值必须是Optional
三、Demo
package com.chentongwei.java8.optional;import lombok.AllArgsConstructor;import lombok.Data;import lombok.NoArgsConstructor;import java.util.Optional;/*** @author chentongwei@baidu-mgame.com 2018-12-14 18:28:07* @Desc Optional api测试*/public class OptionalTest { public static void main(String[] args) { testEmpty(); testOf(); testOfNullable(); testIsPresent(); testIfPresent(); testGet(); testOrElse(); testOrElseGet(); testOrElseThrow(); testFilter(); testMap(); } /** * Optional.empty():创建一个空的Optional实例。new Optional<>(); */ private static void testEmpty() { Optional optionalObj = Optional.empty(); // Optional.empty // 为什么输出这个,不多BB,自己去看Optional类的toString()方法源码好吧? System.out.println(optionalObj); } /** * Optional.of(T t):创建一个包含t值的Optional实例。若t==null,则get的时候会出现空指针。 */ private static void testOf() { /* * java.lang.NullPointerException * 为什么抛空指针?我求你了,自己看源码好吧?就一两句话,从这刻起锻炼自己读源码的意识。 */ Optional optionalNull = Optional.of(null); System.out.println(optionalNull); Optional optionalObj = Optional.of(new Obj("test")); // Optional[Obj(name=test)] System.out.println(optionalObj); } /** * Optional.ofNullable(T t):是empty和of的结合体,创建一个包含t值的Optional实例。不会出现空指针,若t==null则返回空的Optional实例 */ private static void testOfNullable() { /* * Optional.empty * 为什么这里就不抛空指针?我求你了,自己看源码好吧?就一两句话,从这刻起锻炼自己读源码的意识。 */ Optional optionalNull = Optional.ofNullable(null); System.out.println(optionalNull); Optional optionalObj = Optional.ofNullable(newObj("test")); // Optional[Obj(name=test)] System.out.println(optionalObj); } /** * isPresent():判断此值是否是null。true:不是null;false:是null */ private static void testIsPresent() { Optional optionalObj = Optional.ofNullable(null); boolean present = optionalObj.isPresent(); // false System.out.println(present); Optional optionalObj2 = Optional.ofNullable(newObj("test")); boolean present2 = optionalObj2.isPresent(); // true System.out.println(present2); } /** * ifPresent(Consumer consumer):如果值不是空,则执行consumer代码片段逻辑 */ private static void testIfPresent() { Optional optionalObj = Optional.ofNullable(null); /* * 什么都没输出,想了解底层看源码。 */ optionalObj.ifPresent(o -> System.out.println(o.getName())); Optional optionalObj2 = Optional.ofNullable(newObj("test")); // test optionalObj2.ifPresent(o -> System.out.println(o.getName())); } /** * get():获取此值,若值是null,则会抛出NoSuchElementException("No value present"); */ private static void testGet() { Optional optionalObj = Optional.ofNullable(null); // java.util.NoSuchElementException: No value present Obj obj = optionalObj.get(); System.out.println(obj); Optional optionalObj2 = Optional.ofNullable(newObj("test")); Obj obj2 = optionalObj2.get(); // Obj(name=test) System.out.println(obj2); } /** * orElse(T other):若值不是null则返回当前值,否则返回other,有效避免空指针。 */ private static void testOrElse() { Optional optionalObj = Optional.ofNullable(null); // 如果optionalObj==null,则创建Obj("haha") Obj obj = optionalObj.orElse(new Obj("haha")); // Obj(name=haha) System.out.println(obj); Optional optionalObj2 = Optional.ofNullable(newObj("test")); Obj obj2 = optionalObj2.orElse(new Obj("haha")); // Obj(name=test) System.out.println(obj2); } /** * orElseGet(Supplier s):若值不是null则返回当前值,否则返回s获取的值。有效避免空指针。 */ private static void testOrElseGet() { Optional optionalObj = Optional.ofNullable(null); // 如果optionalObj==null,则创建Obj("") Obj obj = optionalObj.orElseGet(Obj::new); // Obj(name=null) System.out.println(obj); Optional optionalObj2 = Optional.ofNullable(newObj("test")); Obj obj2 = optionalObj2.orElseGet(Obj::new); // Obj(name=test) System.out.println(obj2); } /** * orElseThrow(Supplier extends X> exceptionSupplier):若值不是null则返回当前值,否则抛出异常。 */ private static void testOrElseThrow() { Optional optionalObj = Optional.ofNullable(null); // 如果optionalObj==null,则抛出指定异常 // java.lang.ArithmeticException Obj obj = optionalObj.orElseThrow(ArithmeticException::new); System.out.println(obj); // 和上面一样,只是不同写法 Optional optionalObj2 = Optional.ofNullable(null); // java.lang.RuntimeException: exception Obj obj2 = optionalObj2.orElseThrow(() -> newRuntimeException("exception")); System.out.println(obj2); Optional optionalObj3 = Optional.ofNullable(newObj("test")); Obj obj3 =optionalObj3.orElseThrow(NullPointerException::new); // Obj(name=test) System.out.println(obj3); } /** * filter(Predicate super T> predicate):根据某种规则进行过滤。 */ private static void testFilter() { Optional optionalObj = Optional.ofNullable(newObj("test")); Obj obj1 = optionalObj.filter(obj -> obj.getName() != null).get(); // Obj(name=test) System.out.println(obj1); Optional optionalObj2 = Optional.ofNullable(newObj("test")); // java.util.NoSuchElementException: No value present,因为filter没找到满足的条件,返回了empty(),然后针对empty()做个get操作。 // 当然我们可以用orElse来避免 Obj obj2 = optionalObj2.filter(obj -> !obj.getName().equals("test")).get(); System.out.println(obj2); } /** * map(Function f):如果有值对其处理,并返回处理后的Optional,否则返回Optional.empty() */ private static void testMap() { String test = Optional.ofNullable(new Obj()).map(obj ->obj.getName()).orElse("test"); // test System.out.println(test); } /** * flatMap(Function mapper):与map类似,要求返回值必须是Optional。下面的flatMap实战中讲解。 */}@NoArgsConstructor@AllArgsConstructor@Dataclass Obj { private String name;}
四、flatMap实战
常规处理空指针方式
@Datapublic class Person { private Car car;}@Datapublic class Car { private Insurance insurance;}@Datapublic class Insurance { private String name;}package com.chentongwei.java8.optional;/*** @author chentongwei@baidu-mgame.com 2018-12-14 16:11:37* @Desc*/public class Null { public static void main(String[] args) { // 空指针异常,没悬念。因为我们没new Car()也没有newInsurance() getInsuranceName(new Person()); // 虽然不报错,但是代码完全不可读。 getInsuranceNameByDeepDoubts(new Person()); // 虽然不报错,但是也很啰嗦了。 getInsuranceNameByMulitExit(new Person()); } /** * 常见解决null问题的方案之一 * * @param person:人 * @return */ private static String getInsuranceNameByDeepDoubts(Personperson) { if (null != person) { Car car = person.getCar(); if (null != car) { Insurance insurance = car.getInsurance(); if (null != insurance) { return insurance.getName(); } } } return "null"; } /** * 常见解决null问题的方案之二 * * @param person:人 * @return */ private static String getInsuranceNameByMulitExit(Person person) { final String defaultValue = "null"; if (null == person) { return defaultValue; } Car car = person.getCar(); if (null == car) { return defaultValue; } Insurance insurance = car.getInsurance(); if (null == insurance) { return defaultValue; } return insurance.getName(); } /** * 获取某人的车险名称 * * @param person:人 * @return */ private static String getInsuranceName(Person person) { return person.getCar().getInsurance().getName(); }}
Optional处理空指针方式
@Datapublic class Person2 { private Optional car;}@Datapublic class Car2 { private Optional insurance;}@Datapublic class Insurance { private String name;}package com.chentongwei.java8.optional;import java.util.Optional;/*** @author chentongwei@baidu-mgame.com 2018-12-14 19:16:49* @Desc*/public class FlatMapTest { public static void main(String[] args) { // unkonwn Optional.ofNullable(test(null)).ifPresent(System.out::println); } private static String test(Person2 person2) { return Optional.ofNullable(person2) // Person2::getCar返回Optional,所以用flatMap而不是map .flatMap(Person2::getCar) // Car2::getInsurance返回Optional,所以用flatMap而不是map .flatMap(Car2::getInsurance) // 用map拿到name .map(Insurance::getName) // 若name是空的,则输出unknown,防止空指针 .orElse("unkonwn"); }}
五、注意
- 巧妙运用各个API,比如orElse避免空指针等。会让你代码更好看更安全。
- 一定要去阅读此类源码,因为你会发现及其的简单,一看就懂。