一文掌握 Java8 的 Optional 的 6 种操作

{"type":"doc","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"你好,我是看山。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Java8 中引入了一个特别有意思类:","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Optional","attrs":{}}],"attrs":{}},{"type":"text","text":",一个可以让我们更加轻松的避免 NPE(空指针异常,NullPointException)的工具。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"很久很久以前,为了避免 NPE,我们会写很多类似","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"if (obj != null) {}","attrs":{}}],"attrs":{}},{"type":"text","text":"的代码,有时候忘记写,就可能出现 NPE,造成线上故障。在 Java 技术栈中,如果谁的代码出现了 NPE,有极大的可能会被笑话,这个异常被很多人认为是低级错误。","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Optional","attrs":{}}],"attrs":{}},{"type":"text","text":"的出现,可以让大家更加轻松的避免因为低级错误被嘲讽的概率。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"定义示例数据","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"先定义待操作对象,万能的","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Student","attrs":{}}],"attrs":{}},{"type":"text","text":"类和","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Clazz","attrs":{}}],"attrs":{}},{"type":"text","text":"类(用到了 lombok 和 guava):","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"@Data\n@AllArgsConstructor\n@NoArgsConstructor\npublic class Clazz {\n private String id;\n private String name;\n}\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"@Data\n@AllArgsConstructor\n@NoArgsConstructor\npublic class Student {\n private String id;\n private String name;\n private Clazz clazz;\n}\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"然后定义一组测试数据:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"final Clazz clazz1 = new Clazz(\"1\", \"高一一班\");\n\nfinal Student s1 = new Student(\"1\", \"张三\", clazz1);\nfinal Student s2 = new Student(\"2\", \"李四\", null);\n\nfinal List students = Lists.newArrayList(s1, s2);\nfinal List emptyStudents = Lists.newArrayList();\nfinal List nullStudents = null;\n","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"创建实例:of、ofNullable","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"为了控制生成实例的方式,也是为了收紧空值","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Optional","attrs":{}}],"attrs":{}},{"type":"text","text":"的定义,","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Optional","attrs":{}}],"attrs":{}},{"type":"text","text":"将构造函数定义为","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"private","attrs":{}}],"attrs":{}},{"type":"text","text":"。想要创建","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Optional","attrs":{}}],"attrs":{}},{"type":"text","text":"实例,可以借助","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"of","attrs":{}}],"attrs":{}},{"type":"text","text":"和","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"ofNullable","attrs":{}}],"attrs":{}},{"type":"text","text":"两个方法实现。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"这两个方法的区别在于:","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"of","attrs":{}}],"attrs":{}},{"type":"text","text":"方法传入的参数不能是","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"null","attrs":{}}],"attrs":{}},{"type":"text","text":"的,否则会抛出","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"NullPointerException","attrs":{}}],"attrs":{}},{"type":"text","text":"。所以,对于可能是","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"null","attrs":{}}],"attrs":{}},{"type":"text","text":"的结果,一定使用","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"ofNullable","attrs":{}}],"attrs":{}},{"type":"text","text":"。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"代码如下:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"Optional.of(students);\nOptional.of(emptyStudents);\nOptional.ofNullable(nullStudents);\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"Optional","attrs":{}}],"attrs":{}},{"type":"text","text":"类中还有一个静态方法:","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"empty","attrs":{}}],"attrs":{}},{"type":"text","text":",这个方法直接返回了内部定义的一个常量","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Optional> EMPTY = new Optional<>()","attrs":{}}],"attrs":{}},{"type":"text","text":",这个常量的","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"value","attrs":{}}],"attrs":{}},{"type":"text","text":"是","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"null","attrs":{}}],"attrs":{}},{"type":"text","text":"。","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"ofNullable","attrs":{}}],"attrs":{}},{"type":"text","text":"方法也是借助了","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"empty","attrs":{}}],"attrs":{}},{"type":"text","text":"实现","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"null","attrs":{}}],"attrs":{}},{"type":"text","text":"的包装:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"public static Optional ofNullable(T value) {\n return value == null ? empty() : of(value);\n}\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"所以说,对于","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"null","attrs":{}}],"attrs":{}},{"type":"text","text":"的","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Optional","attrs":{}}],"attrs":{}},{"type":"text","text":"包装类,指向的都是相同的实例对象,","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Optional.empty() == Optional.ofNullable(null)","attrs":{}}],"attrs":{}},{"type":"text","text":"返回的是","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"true","attrs":{}}],"attrs":{}},{"type":"text","text":"。换句话说,空","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Optional","attrs":{}}],"attrs":{}},{"type":"text","text":"是单例的。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"为了方便描述,下文中对值为","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"null","attrs":{}}],"attrs":{}},{"type":"text","text":"的","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Optional","attrs":{}}],"attrs":{}},{"type":"text","text":"统称为“","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"空","attrs":{}},{"type":"codeinline","content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"Optional","attrs":{}}],"attrs":{}},{"type":"text","text":"”。","attrs":{}}]}],"attrs":{}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"获取数据:get","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"Optional","attrs":{}}],"attrs":{}},{"type":"text","text":"的","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"get","attrs":{}}],"attrs":{}},{"type":"text","text":"方法有些坑人,先看下它的源码:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"public T get() {\n if (value == null) {\n throw new NoSuchElementException(\"No value present\");\n }\n return value;\n}\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"也就是说,","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Optional","attrs":{}}],"attrs":{}},{"type":"text","text":"值为空时,使用","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"get","attrs":{}}],"attrs":{}},{"type":"text","text":"方法将抛出","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"NoSuchElementException","attrs":{}}],"attrs":{}},{"type":"text","text":"异常。如果不想抛出异常,或者能够 100%确定不是空","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Optional","attrs":{}}],"attrs":{}},{"type":"text","text":",或者使用","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"isPresent","attrs":{}}],"attrs":{}},{"type":"text","text":"方法判断。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如果能 100%确定不是空","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Optional","attrs":{}}],"attrs":{}},{"type":"text","text":",那就没有必要使用","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Optional","attrs":{}}],"attrs":{}},{"type":"text","text":"包装,直接返回即可。如果需要使用","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"isPresent","attrs":{}}],"attrs":{}},{"type":"text","text":"方法,那就和直接判空没有区别了。所以,无论是第一种情况还是第二种情况,都违背了设计这个类的初衷。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"值为空判断:isPresent、ifPresent","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"isPresent","attrs":{}}],"attrs":{}},{"type":"text","text":"用来判断值是否为空,类似于","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"obj != null","attrs":{}}],"attrs":{}},{"type":"text","text":",","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"ifPresent","attrs":{}}],"attrs":{}},{"type":"text","text":"可以传入一个","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Consumer","attrs":{}}],"attrs":{}},{"type":"text","text":"操作,当值不为空的时候,会执行","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Consumer","attrs":{}}],"attrs":{}},{"type":"text","text":"函数。比如:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"final Optional> nullValue = Optional.ofNullable(nullStudents);\n\nif (nullValue.isPresent()) {\n System.out.println(\"value: \" + nullValue.get());\n}\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"上面的方法等价于:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"nullValue.ifPresent(value -> System.out.println(\"value: \" + value));\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"isPresent","attrs":{}}],"attrs":{}},{"type":"text","text":"判断的写法上是不是感觉很熟悉,感觉可以直接写为:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"if (nullStudents != null) {\n System.out.println(\"value: \" + nullStudents);\n}\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"对于","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"isPresent","attrs":{}}],"attrs":{}},{"type":"text","text":",如果是在自己可控的代码范围内,完全没有必要将值封装之后再判空。对于自己不可控的代码,后续的","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"filter","attrs":{}}],"attrs":{}},{"type":"text","text":"或者","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"map","attrs":{}}],"attrs":{}},{"type":"text","text":"方法可能比","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"isPresent","attrs":{}}],"attrs":{}},{"type":"text","text":"更好用一些。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"对于","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"ifPresent","attrs":{}}],"attrs":{}},{"type":"text","text":",在使用的时候会有一些限制,就是必须是非空","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Optional","attrs":{}}],"attrs":{}},{"type":"text","text":"的时候,在会执行传入的","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Consumer","attrs":{}}],"attrs":{}},{"type":"text","text":"函数。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"值处理:map、flatMap","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"map","attrs":{}}],"attrs":{}},{"type":"text","text":"和","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"flatMap","attrs":{}}],"attrs":{}},{"type":"text","text":"是对","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Optional","attrs":{}}],"attrs":{}},{"type":"text","text":"的值进行操作的方法,区别在于,","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"map","attrs":{}}],"attrs":{}},{"type":"text","text":"会将结果包装到","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Optional","attrs":{}}],"attrs":{}},{"type":"text","text":"中返回,","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"flatMap","attrs":{}}],"attrs":{}},{"type":"text","text":"不会。但是两个方法返回值都是","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Optional","attrs":{}}],"attrs":{}},{"type":"text","text":"类型,这也就要求,","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"flatMap","attrs":{}}],"attrs":{}},{"type":"text","text":"的方法函数返回值需要是","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Optional","attrs":{}}],"attrs":{}},{"type":"text","text":"类型。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我们来看看","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"map","attrs":{}}],"attrs":{}},{"type":"text","text":"的实现:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"public Optional map(Function super T, ? extends U> mapper) {\n Objects.requireNonNull(mapper);\n if (!isPresent())\n return empty();\n else {\n return Optional.ofNullable(mapper.apply(value));\n }\n}\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"可以看到,如果","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Optional","attrs":{}}],"attrs":{}},{"type":"text","text":"的值为空,","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"map","attrs":{}}],"attrs":{}},{"type":"text","text":"直接返回","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Optional.EMPTY","attrs":{}}],"attrs":{}},{"type":"text","text":",否则会执行函数结果,并使用","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Optional.ofNullable","attrs":{}}],"attrs":{}},{"type":"text","text":"包装并返回。也即是说,只要类结构允许,我们可以一直","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"map","attrs":{}}],"attrs":{}},{"type":"text","text":"下去,就像是扒洋葱,一层一层,直到核心。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"比如,我们要获取","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"s2","attrs":{}}],"attrs":{}},{"type":"text","text":"所在班级名称,在定义的时候,我们将","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"s2","attrs":{}}],"attrs":{}},{"type":"text","text":"的","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"clazz","attrs":{}}],"attrs":{}},{"type":"text","text":"属性定义为 null,如果以前需要写为:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"String clazzNameOld;\nif (s2 != null && s2.getClazz() != null && s2.getClazz().getName() != null) {\n clazzNameOld = s2.getClazz().getName();\n} else {\n clazzNameOld = \"DEFAULT_NAME\";\n}\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"现在借助","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Optional","attrs":{}}],"attrs":{}},{"type":"text","text":"可以写为:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"final String clazzName = Optional.ofNullable(s2)\n .map(Student::getClazz)\n .map(Clazz::getName)\n .orElse(\"DEFAULT_NAME\");\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"从代码上似乎没有多大改变,但是如果","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Clazz","attrs":{}}],"attrs":{}},{"type":"text","text":"内部还有类对象。或者,我们在","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"if","attrs":{}}],"attrs":{}},{"type":"text","text":"判断的时候,少写一层检查呢?而且,","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"map","attrs":{}}],"attrs":{}},{"type":"text","text":"的精巧还在于它的返回值永远是","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Optional","attrs":{}}],"attrs":{}},{"type":"text","text":",这样,我们可以重复调用","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"map","attrs":{}}],"attrs":{}},{"type":"text","text":"方法,而不需要中间被打断,增加各种判空逻辑。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"值为空的处理:orElse、orElseGet、orElseThrow","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"这几个方法可以与","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"map","attrs":{}}],"attrs":{}},{"type":"text","text":"操作结合,一起完成对象操作。当值为空时,","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"orElse","attrs":{}}],"attrs":{}},{"type":"text","text":"和","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"orElseGet","attrs":{}}],"attrs":{}},{"type":"text","text":"返回默认值,","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"orElseThrow","attrs":{}}],"attrs":{}},{"type":"text","text":"抛出指定的异常。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"orElse","attrs":{}}],"attrs":{}},{"type":"text","text":"和","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"orElseGet","attrs":{}}],"attrs":{}},{"type":"text","text":"的区别是,","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"orElse","attrs":{}}],"attrs":{}},{"type":"text","text":"方法传入的参数是明确的默认值,","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"orElseGet","attrs":{}}],"attrs":{}},{"type":"text","text":"方法传入的参数是获取默认值的函数。如果默认值的构造过程比较复杂,需要经过一系列的运算逻辑,那一定要使用","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"orElseGet","attrs":{}}],"attrs":{}},{"type":"text","text":",因为","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"orElseGet","attrs":{}}],"attrs":{}},{"type":"text","text":"是在值为空的时候,才会执行函数,并返回默认值,如果值不为空,则不会执行函数,相比于","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"orElse","attrs":{}}],"attrs":{}},{"type":"text","text":"而言,减少了一次构造默认值的过程。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"同样以上面的例子:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"orElse","attrs":{}}],"attrs":{}},{"type":"text","text":"的写法:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"final String clazzName = Optional.ofNullable(s2)\n .map(Student::getClazz)\n .map(Clazz::getName)\n .orElse(null);\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"orElseGet","attrs":{}}],"attrs":{}},{"type":"text","text":"的写法:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"final String clazzName = Optional.of(s2)\n .map(Student::getClazz)\n .map(Clazz::getName)\n .orElseGet(() -> null);\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如果","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"clazz","attrs":{}}],"attrs":{}},{"type":"text","text":"属性一定不为空,为空则返回异常,可以使用","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"orElseThrow","attrs":{}}],"attrs":{}},{"type":"text","text":":","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"final String clazzName = Optional.of(s2)\n .map(Student::getClazz)\n .map(Clazz::getName)\n .orElseThrow(() -> new IllegalArgumentException(\"clazz属性不合法\"));\n","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"条件过滤:filter","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"filter","attrs":{}}],"attrs":{}},{"type":"text","text":"方法提供的是值验证,如果值验证为 true,返回当前值;否则,返回空","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Optional","attrs":{}}],"attrs":{}},{"type":"text","text":"。比如,我们要遍历","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"students","attrs":{}}],"attrs":{}},{"type":"text","text":",找到班级属性为空的,打印学生id:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"for (final Student s : students) {\n Optional.of(s)\n .filter(x -> x.getClazz() == null)\n .ifPresent(x -> System.out.println(x.getId()));\n}\n","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"其他:equals、hashCode、toString","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"Optional","attrs":{}}],"attrs":{}},{"type":"text","text":"重写了这三个方法。因为","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Optional","attrs":{}}],"attrs":{}},{"type":"text","text":"可以认为是包装类,所以还是围绕这被包装的值重写这三个方法。下面给出这三个方法的源码:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"public boolean equals(Object obj) {\n // 同一对象判断\n if (this == obj) {\n return true;\n }\n\n // 类型判断\n if (!(obj instanceof Optional)) {\n return false;\n }\n\n Optional> other = (Optional>) obj;\n // 最终还是值的判断\n return Objects.equals(value, other.value);\n}\n\npublic int hashCode() {\n // 直接返回值的hashCode\n return Objects.hashCode(value);\n}\n\npublic String toString() {\n return value != null\n ? String.format(\"Optional[%s]\", value) // 用到了值的toString结果\n : \"Optional.empty\";\n}\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"equals","attrs":{}}],"attrs":{}},{"type":"text","text":"方法,","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Optional.of(s1).equals(Optional.of(s2))","attrs":{}}],"attrs":{}},{"type":"text","text":"完全等价于","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"s1.equals(s2)","attrs":{}}],"attrs":{}},{"type":"text","text":"。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"hashCode","attrs":{}}],"attrs":{}},{"type":"text","text":"方法,直接返回的是值的hashCode,如果是空","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Optional","attrs":{}}],"attrs":{}},{"type":"text","text":",返回的是0。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"toString","attrs":{}}],"attrs":{}},{"type":"text","text":"方法,为了能够识别是","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Optional","attrs":{}}],"attrs":{}},{"type":"text","text":",将打印数据包装了一下。如果是空","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Optional","attrs":{}}],"attrs":{}},{"type":"text","text":",返回的是字符串“Optional.empty”;如果是非空,返回是是“Optional[值的toString]”。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"文末总结","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"NPE 之所以讨厌,就是只要出现 NPE,我们就能够解决。但是一旦出现,都已经是事后,可能已经出现线上故障。偏偏在 Java 语言中,NPE 又很容易出现。","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Optional","attrs":{}}],"attrs":{}},{"type":"text","text":"提供了模板方法,有效且高效的避免 NPE。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"接下来,我们针对上面的使用,总结一下:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"numberedlist","attrs":{"start":1,"normalizeStart":1},"content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"Optional","attrs":{}}],"attrs":{}},{"type":"text","text":"是一个包装类,且不可变,不可序列化","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"text","text":"没有公共构造函数,创建需要使用","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"of","attrs":{}}],"attrs":{}},{"type":"text","text":"、","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"ofNullable","attrs":{}}],"attrs":{}},{"type":"text","text":"方法","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":3,"align":null,"origin":null},"content":[{"type":"text","text":"空","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Optional","attrs":{}}],"attrs":{}},{"type":"text","text":"是单例,都是引用","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Optional.EMPTY","attrs":{}}],"attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":4,"align":null,"origin":null},"content":[{"type":"text","text":"想要获取","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Optional","attrs":{}}],"attrs":{}},{"type":"text","text":"的值,可以使用","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"get","attrs":{}}],"attrs":{}},{"type":"text","text":"、","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"orElse","attrs":{}}],"attrs":{}},{"type":"text","text":"、","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"orElseGet","attrs":{}}],"attrs":{}},{"type":"text","text":"、","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"orElseThrow","attrs":{}}],"attrs":{}}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"另外,还有一些实践上的建议:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"numberedlist","attrs":{"start":1,"normalizeStart":1},"content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"text","text":"使用","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"get","attrs":{}}],"attrs":{}},{"type":"text","text":"方法前,必须使用","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"isPresent","attrs":{}}],"attrs":{}},{"type":"text","text":"检查。但是使用","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"isPresent","attrs":{}}],"attrs":{}},{"type":"text","text":"前,先思考下是否可以使用","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"orElse","attrs":{}}],"attrs":{}},{"type":"text","text":"、","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"orElseGet","attrs":{}}],"attrs":{}},{"type":"text","text":"等方法代替实现。","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"orElse","attrs":{}}],"attrs":{}},{"type":"text","text":"和","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"orElseGet","attrs":{}}],"attrs":{}},{"type":"text","text":",优先选择","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"orElseGet","attrs":{}}],"attrs":{}},{"type":"text","text":",这个是惰性计算","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":3,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"Optional","attrs":{}}],"attrs":{}},{"type":"text","text":"不要作为参数或者类属性,可以作为返回值","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":4,"align":null,"origin":null},"content":[{"type":"text","text":"尽量将","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"map","attrs":{}}],"attrs":{}},{"type":"text","text":"、","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"filter","attrs":{}}],"attrs":{}},{"type":"text","text":"的函数参数抽出去作为单独方法,这样能够保持链式调用","attrs":{}}]}]}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"推荐阅读","attrs":{}}]},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"https://xie.infoq.cn/article/50324deb1efcf3845113e341f","title":"","type":null},"content":[{"type":"text","text":"https://xie.infoq.cn/article/50324deb1efcf3845113e341f","attrs":{}}]}]}]}],"attrs":{}},{"type":"horizontalrule","attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/9e/9e305acd1cca75053c144cb28adc6061.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}}]}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章