Java基础系列-Optional
原创文章,转载请标注出处:https://www.cnblogs.com/V1haoge/p/10755368.html
一、概述
Optional的引入是为了解决null的问题,那么到底是解决null的什么问题呢?
我们知道当我们针对null调用方法的之后,就会抛出空指针异常,Optional就是为了解决这个问题而来的。
Optional通过封装目标对象的方式来表示,当我们使用的时候,Optional是必然存在的,因为如果结果为null,会返回一个固定的EMPTY实例,这样就不会存在null引用的问题了。
那该如何来使用Optional呢?
我们不能滥用Optional,只有在逻辑上(业务上)可能为null时才使用Optional来封装目标对象,如果逻辑上(业务上)肯定不可能为null时,就不要使用Optional封装对象,这样当阅读代码的人看到有Optional则表示目标对象是可以为null的。
这样之后,如果程序中又出现了null指针异常,那么只能是你的代码逻辑有误,而不可能是非逻辑原因了,也就是不该为null的时候出现了null,这肯定是你逻辑搞错了。
二、Optional
2.1 创建Optional实例
2.1.1 创建一个空的Optional
public class OptionalTest {
public static void main(String[] args) {
Optional<String> o = Optional.empty();// 创建一个空Optional
}
}
2.1.2 创建一个有值的Optional
public class OptionalTest {
public static void main(String[] args) {
Optional<String> op = Optional.of("123");// 创建一个目标对象必须有值的Optional
}
}
这种创建方式,如果of的参数为null,则直接抛出异常。
2.1.3 创建一个可为空的Optional
public class OptionalTest {
public static void main(String[] args) {
Optional<String> opt = Optional.ofNullable(null);// 创建一个目标对象可为null的Optional
}
}
2.2 中间操作-处理Optional
2.2.1 filter
这个filter是一个校验器,由于Optional中也只有一个元素,称其为过滤有点太大了,如果Optional中的元素满足给定的校验条件,则将封装元素的Optional返回,否则返回空的Optional。
public class OptionalTest {
public static void main(String[] args) {
filterTest();
}
public static void filterTest(){
Optional<String> os = Optional.of("123456").filter(e -> e.length()>7);
System.out.println(os.isPresent());
}
}
执行结果:
false
因为字符串“123456”长度小于7,所以返回一个空的Optional。
2.2.2 map
map是映射之意,就是针对Optional封装的元素进行操作,然后返回一个封装着操作结果的新的Optional。
public class OptionalTest {
public static void main(String[] args) {
mapTest();
}
public static void mapTest(){
Optional<Integer> oi = Optional.of("abcdefg").map(e -> e.length());
System.out.println(oi.get());
}
}
执行结果:
7
2.2.3 flatMap
这个方法是扁平化映射,所谓扁平就是处理嵌套的Optional。
比如有一个Person类,其中有一个Optional类型的字段name,我们在别处获取到了一个Optional类型的实例,现在想要获取到这个Person的的姓名,这就是嵌套的Optional。
class Person{
Optional<String> name;
public Person(String name){
this.name = Optional.of(name);
}
public Optional<String> getName(){
return name;
}
}
如果我们使用map获取到的是如下的:
public class OptionalTest {
public static void main(String[] args) {
flatMapTest();
}
public static void flatMapTest(){
Optional<Person> op = Optional.of(new Person("huahua"));
Optional<Optional<String>> oos = op.map(Person::getName);
String name = oos.get().orElseGet(()->"noName");
System.out.println(name);
}
}
而我们使用flatMap的话就可以是这样的:
public class OptionalTest {
public static void main(String[] args) {
flatMapTest();
}
public static void flatMapTest(){
Optional<Person> op = Optional.of(new Person("huahua"));
Optional<String> os = op.flatMap(Person::getName);
String name = os.orElseGet(()->"noName");
System.out.println(name);
}
}
嵌套的Optional要获取到目标对象,必须通过多次去壳才行,这也是使用map映射的原理,但是使用flatMap,扁平化功能,一次去壳操作就完成了。
2.3 从Optional中获取目标值
有四种方式:
- public T get():直接获取Optional中的值,如果是空的要抛出NoSuchElementException异常
- public T orElse(T other):如果Optional不为空,则将值返回,否则返回指定的other(默认值)
- public T orElseGet(Supplier<? extends T> other):如果Optional不为空,则返回值,否则将通过指定方式other生成的值返回
- public T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X:如果Optional不为空,返回值,否则抛出由指定的exceptionSupplier生成的异常
public class OptionalTest {
public static void main(String[] args) {
getTest();
orElseTest();
}
public static void getTest(){
Optional<String> os = Optional.of("123456");
System.out.println(os.get());
}
public static void orElseTest(){
Optional<String> os = Optional.empty();
System.out.println(os.orElse("default"));
System.out.println(os.orElseGet(()->"default"));
System.out.println(os.orElseThrow(RuntimeException::new));
}
}
执行结果:
123456
default
default
Exception in thread "main" java.lang.RuntimeException
at java.util.Optional.orElseThrow(Optional.java:290)
at com.dh.stream.OptionalTest.orElseTest(OptionalTest.java:29)
at com.dh.stream.OptionalTest.main(OptionalTest.java:17)
三、使用方式
Optional使用时不能直接get,这时会走进老路,get的时候可能为null,就会抛出异常,这时候你就会想要在get之前进行isPresent判断,这个不使用Optional又有什么区别的。
我们使用Optional就是为了简化null判断,所以拒绝使用get方法,Optional提供了正确使用的方法是:orElse、orElseGet、orElseThrow三个方法。
使用orElse方法,我们可以从非空的Optional中获取到值,如果是空的Optional,可以返回orElse方法参数指定的默认值。
使用orElseGet方法,我们可以在空的Optional的情况下主动构建一个默认返回结果。
orElseThrow方法,在空Optional的情况下会抛出一个指定的异常。
四、总结
说了这么多,最终是为了在开发中使用Optional,正如开始时说的,我们要明确Optional规避的是那种null,不能在所有的地方都使用它。
当项目的业务规则下某个对象可能为null(就是业务允许的null),这种情况下,出现null是正常现象,这种情况需要规避,我们使用Optional封装目标对象,保证不会存在null调用抛出空指针。
但是如果在业务规则下某个对象不可能为null(就是业务不允许为null),这种情况下,出现null就是程序出错了,并不是正常现象,这种时候我们不能用Optional去封装目标对象来规避问题,而是要直接使用,一旦出错就可以及时的排查问题,不至于被Optional将问题给隐藏掉。
Java基础系列-Optional的更多相关文章
- Java基础系列-Collector和Collectors
原创作品,可以转载,但是请标注出处地址:https://www.cnblogs.com/V1haoge/p/10748925.html 一.概述 Collector是专门用来作为Stream的coll ...
- 2015年12月28日 Java基础系列(六)流
2015年12月28日 Java基础系列(六)流2015年12月28日 Java基础系列(六)流2015年12月28日 Java基础系列(六)流
- Java基础系列--static关键字
原创作品,可以转载,但是请标注出处地址:http://www.cnblogs.com/V1haoge/p/8477914.html 一.概述 static关键字是Java诸多关键字中较常使用的一个,从 ...
- Java基础系列-ArrayList
原创文章,转载请标注出处:<Java基础系列-ArrayList> 一.概述 ArrayList底层使用的是数组.是List的可变数组实现,这里的可变是针对List而言,而不是底层数组. ...
- Java基础系列-二进制操作
原创文章,转载请标注出处:<Java基础系列-二进制操作> 概述 Java源码中涉及到大量的二进制操作,非常的复杂,但非常的快速. Java二进制表示法 首先了解下二进制,二进制是相对十进 ...
- Java基础系列-equals方法和hashCode方法
原创文章,转载请标注出处:<Java基础系列-equals方法和hashCode方法> 概述 equals方法和hashCode方法都是有Object类定义的. publi ...
- Java基础系列-Comparable和Comparator
原创文章,转载请标注出处:<Java基础系列-Comparable和Comparator> 一.概述 Java中的排序是由Comparable和Comparator这两个接 ...
- Java基础系列--HashMap(JDK1.8)
原创作品,可以转载,但是请标注出处地址:https://www.cnblogs.com/V1haoge/p/10022092.html Java基础系列-HashMap 1.8 概述 HashMap是 ...
- 夯实Java基础系列1:Java面向对象三大特性(基础篇)
本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 [https://github.com/h2pl/Java-Tutorial](https: ...
随机推荐
- ReplayingDecoder 解码器:别以为我有多厉害,也只不过是使用了一下装饰器模式而已~
原文地址 一.设计模式为啥老是用不好? 想要写出更屌的代码,提高代码的健壮性和可扩展性,那么设计模式可谓是必学的技能. 关于学习设计模式,大家可能都觉得设计模式的概念太过于抽象,理解起来有点费劲:又或 ...
- Spark-shell 报错:Failed to get database default, returning NoSuchObjectException
Spark-shell 执行sql查询报错: 20/08/24 15:33:59 WARN metastore.ObjectStore: Failed to get database default, ...
- mysql建数据库的字符集与排序规则说明
本文转自https://blog.csdn.net/qq_38224812/article/details/80745868,感谢作者,自己留存已备他日使用 1.字符集说明: 一般选择utf8.下面介 ...
- Vue开源项目使用探索
前言 本文记录一次使用Vue开源项目的过程. 寻找Vue开源项目 要使用Vue开源项目就必须先找到一个,我们去Github上搜索[后台],然后使用Vue分类进行检索,找到排名第一的开源框架进行下载—v ...
- C# 获取当前月的月初和月末
/// <summary> /// 获取当前月的月末日期 /// </summary> /// <returns></returns> public s ...
- ElasticSearch7.6.1 安装及其head插件安装
本来打算写一篇ES和Solr的差别的,后来想想算了简单说说吧, 如果是对已存在数据建立完成索引的情况下,Solr更快 一但进行索引的操作的时候,Solr的IO是阻塞的 对于大数据量的实时检索,还是El ...
- Java使用JDBC连接Oracle数据库
import java.sql.Connection; import java.sql.Driver; import java.sql.DriverManager; /** * @author liu ...
- datattable循环读取数据用于循环遍历checkboxlist里的项目
DataTable dt = bptb.GetList("Pro_ID="+id).Tables[0]; foreach (ListItem li in from DataRow ...
- Python算法题:有100只大、中、小骆驼,100框土豆,一只大骆驼可以背3框,中骆驼可以背俩框,小骆驼两只背一筐,问大中小各有多少只骆驼?
1 for x in range(0,100): 2 for y in range(0,100): 3 for z in range(0, 100): 4 if x*3+y*2+0.5*z == 10 ...
- 《Java从入门到失业》第四章:类和对象(4.1):初识类和对象
4类和对象 在第一章曾经简单介绍过,在面向对象的世界里,一切事物皆对象,当解决一个问题的时候,我们先会考虑这个问题会涉及到哪些事物,然后把事物抽象成类,当时还画了一张图如下: 从本章开始,我们一点一点 ...