java.util.Optional<T>

本文深入探讨Java8中Optional类的引入目的与使用方法,旨在避免空指针异常,通过实例展示Optional的各种操作,如创建、判断、转换及异常处理等。

简介

为了避免null导致NullPointerException,JAVA8新增了Optional来避免这种情况的发生。

当变量T存在时, Optional类只是对类简单封装。当变量T不存在时,缺失的值会被建模成一个“空”的Optional对象,由方法Optional.empty()返回。

 null引用和Optional.empty()有什么本质的区别吗?从语义上,可以把它们当作一回事儿,但是实际中它们之间的差别非常大:如果尝试引用一个null, 一定会触发NullPointerException,而Optional.empty()则没这个问题,它是Optional类的一个有效对象,多种场景都能正常调用。

但如果你就是不使用Optional,那么可以理解为你是允许该对象为null。

String name;按照JAVA8约定,这种形式的变量是不允许出现null情况的,如果出现null,则只能说是业务流程出现问题。

Optional<String> name;按照JAVA8约定,这种形式的变量是允许出现null情况的。

方法使用案例

Optional<Car> optCar = Optional.empty();声明一个空的Optional

Optional<Car> optCar = Optional.of(car);依据一个非空值创建Optional

Optional<Car> optCar = Optional.ofNullable(car);可接受null的Optional

Optional<Insurance> optInsurance = Optional.ofNullable(insurance);

Optional<String> name = optInsurance.map(Insurance::getName);可以把Optional对象看成一种特殊的集合数据,它至多包含一个元素。如果Optional包含一个值,那函数就将该值作为参数传递给map,对该值进行转换。如果Optional为空,就什么也不做。使用 map 来从Optional对象中提取和转换值

person.flatMap(Person::getCar).flatMap(Car::getInsurance).map(Insurance::getName).orElse("Unknown");flatMap方法接受一个函数作为参数,这个函数的返回值是另一个流。这个方法会应用到流中的每一个元素,最终形成一个新的流的流。但是flagMap会用流的内容替换每个新生成的流。换句话说,由方法生成的各个流会被合并或者扁平化为一个单一的流。

optInsurance.filter(insurance->"CambridgeInsurance".equals(insurance.getName())).ifPresent(x->System.out.println("ok"));filter方法接受一个谓词作为参数。 如果Optional对象的值存在,并且它符合谓词的条件,filter方法就返回其值;否则它就返回一个空的Optional对象。如果你还记得我们可以将Optional看成最多包含一个元素的Stream对象,这个方法的行为就非常清晰了。 如果Optional对象为空,它不做任何操作,反之,它就对Optional对象中包含的值施加谓词操作。如果该操作的结果为true,它不做任何改变,直接返回该Optional对象,否则就将该值过滤掉,将Optional的值置空。

常用方法API

①get()是这些方法中最简单但又最不安全的方法。如果变量存在,它直接返回封装的变量

值,否则就抛出一个NoSuchElementException异常。所以,除非你非常确定Optional变量一定包含值,否则使用这个方法是个相当糟糕的主意。此外,这种方式即便相对于嵌套式的null检查,也并未体现出多大的改进。

②orElse(T other)允许在Optional对象不包含值时提供一个默认值。

③orElseGet(Supplier<? extends T> other)是orElse方法的延迟调用版, Supplier

方法只有在Optional对象不含值时才执行调用。如果创建默认值是件耗时费力的工作,

应考虑采用这种方式,或者需要非常确定某个方法仅在Optional为空时才进行调用,也可以考虑该方式。

④orElseThrow(Supplier<? extends X> exceptionSupplier)和get方法非常类似,它们遭遇Optional对象为空时都会抛出一个异常,但是使用orElseThrow可以定制希望抛出的异常类型。

⑤ifPresent(Consumer<? super T>)能在变量值存在时执行一个作为参数传入的方法,否则就不进行任何操作。

API列表

1.empty:返回一个空的Optional实例。

2.filter:如果值存在并且满足提供的谓词,就返回包含该值的 Optional对象;否则返回一个空的Optional对象。

3.flatMap:如果值存在,就对该值执行提供的mapping函数调用,返回一个Optional类型的值,否则就返回一个空的Optional对象。

4.get:如果该值存在,将该值用Optional封装返回,否则抛出一个NoSuchElementException异常。

5.ifPresent:如果值存在,就执行使用该值的方法调用,否则什么也不做。

6.isPresent:如果值存在就返回true,否则返回false。

7.map:如果值存在,就对该值执行提供的mapping函数调用。

8.of:将指定值用Optional封装之后返回,如果该值为null,则抛出一个NullPointerException异常。

9.ofNullable:将指定值用Optional封装之后返回,如果该值为null,则返回一个空的Optional对象。

10.orElse:如果有值则将其返回,否则返回一个默认值。

11.orElseGet:如果有值则将其返回,否则返回一个由指定的 Supplier接口生成的值。

12.orElseThrow:如果有值则将其返回,否则抛出一个由指定的 Supplier接口生成的异常。

改造老旧代码

Null转Optional:

Optional<Object> value =

Optional.ofNullable(map.get("key"));

处理异常:

try {

return Optional.of(Integer.parseInt(s));

} catch (NumberFormatException e) {

return Optional.empty();

}

注意事项

①Optional也提供了类似的基础类型:OptionalInt、 OptionalLong以及OptionalDouble。但是这些基础类型却不支持map、flatMap以及filter方法。

②Optional对象无法由基础类型的Optional组合构成,比如:OptionalInt类型的对象,你就不能将其作为方法引用传递给另一个Optional对象的flatMap方法。

③Optional类并未实现Serializable接口。

Error starting ApplicationContext. To display the condition evaluation report re-run your application with 'debug' enabled. 2025-05-17T01:46:29.326+08:00 ERROR 11332 --- [ restartedMain] o.s.boot.SpringApplication : Application run failed org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'clientHttpRequestFactoryBuilder' defined in class path resource [org/springframework/boot/autoconfigure/http/client/HttpClientAutoConfiguration.class]: Failed to instantiate [org.springframework.boot.http.client.ClientHttpRequestFactoryBuilder]: Factory method 'clientHttpRequestFactoryBuilder' threw exception with message: org/apache/hc/client5/http/ssl/TlsSocketStrategy at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:657) ~[spring-beans-6.2.6.jar:6.2.6] at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:645) ~[spring-beans-6.2.6.jar:6.2.6] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1367) ~[spring-beans-6.2.6.jar:6.2.6] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1197) ~[spring-beans-6.2.6.jar:6.2.6] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:569) ~[spring-beans-6.2.6.jar:6.2.6] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:529) ~[spring-beans-6.2.6.jar:6.2.6] at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:339) ~[spring-beans-6.2.6.jar:6.2.6] at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:371) ~[spring-beans-6.2.6.jar:6.2.6] at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:337) ~[spring-beans-6.2.6.jar:6.2.6] at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202) ~[spring-beans-6.2.6.jar:6.2.6] at org.springframework.beans.factory.support.DefaultListableBeanFactory.instantiateSingleton(DefaultListableBeanFactory.java:1221) ~[spring-beans-6.2.6.jar:6.2.6] at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingleton(DefaultListableBeanFactory.java:1187) ~[spring-beans-6.2.6.jar:6.2.6] at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:1122) ~[spring-beans-6.2.6.jar:6.2.6] at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:987) ~[spring-context-6.2.6.jar:6.2.6] at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:627) ~[spring-context-6.2.6.jar:6.2.6] at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:146) ~[spring-boot-3.4.5.jar:3.4.5] at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:753) ~[spring-boot-3.4.5.jar:3.4.5] at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:439) ~[spring-boot-3.4.5.jar:3.4.5] at org.springframework.boot.SpringApplication.run(SpringApplication.java:318) ~[spring-boot-3.4.5.jar:3.4.5] at org.springframework.boot.SpringApplication.run(SpringApplication.java:1362) ~[spring-boot-3.4.5.jar:3.4.5] at org.springframework.boot.SpringApplication.run(SpringApplication.java:1351) ~[spring-boot-3.4.5.jar:3.4.5] at cn.zwz.ZwzApplication.main(ZwzApplication.java:18) ~[classes/:na] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[na:na] at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na] at java.base/java.lang.reflect.Method.invoke(Method.java:569) ~[na:na] at org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.java:50) ~[spring-boot-devtools-3.4.5.jar:3.4.5] Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.boot.http.client.ClientHttpRequestFactoryBuilder]: Factory method 'clientHttpRequestFactoryBuilder' threw exception with message: org/apache/hc/client5/http/ssl/TlsSocketStrategy at org.springframework.beans.factory.support.SimpleInstantiationStrategy.lambda$instantiate$0(SimpleInstantiationStrategy.java:199) ~[spring-beans-6.2.6.jar:6.2.6] at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiateWithFactoryMethod(SimpleInstantiationStrategy.java:88) ~[spring-beans-6.2.6.jar:6.2.6] at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:168) ~[spring-beans-6.2.6.jar:6.2.6] at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:653) ~[spring-beans-6.2.6.jar:6.2.6] ... 26 common frames omitted Caused by: java.lang.NoClassDefFoundError: org/apache/hc/client5/http/ssl/TlsSocketStrategy at org.springframework.boot.http.client.ClientHttpRequestFactoryBuilder.httpComponents(ClientHttpRequestFactoryBuilder.java:97) ~[spring-boot-3.4.5.jar:3.4.5] at org.springframework.boot.http.client.ClientHttpRequestFactoryBuilder.detect(ClientHttpRequestFactoryBuilder.java:200) ~[spring-boot-3.4.5.jar:3.4.5] at org.springframework.boot.autoconfigure.http.client.HttpClientAutoConfiguration.clientHttpRequestFactoryBuilder(HttpClientAutoConfiguration.java:53) ~[spring-boot-autoconfigure-3.4.5.jar:3.4.5] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[na:na] at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na] at java.base/java.lang.reflect.Method.invoke(Method.java:569) ~[na:na] at org.springframework.beans.factory.support.SimpleInstantiationStrategy.lambda$instantiate$0(SimpleInstantiationStrategy.java:171) ~[spring-beans-6.2.6.jar:6.2.6] ... 29 common frames omitted Caused by: java.lang.ClassNotFoundException: org.apache.hc.client5.http.ssl.TlsSocketStrategy at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:641) ~[na:na] at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:188) ~[na:na] at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:525) ~[na:na] ... 37 common frames omitted 进程已结束,退出代码为 1 <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <!-- 模型版本号 --> <modelVersion>4.0.0</modelVersion> <!-- 基本项目信息 --> <groupId>cn.zwz</groupId> <artifactId>s056</artifactId> <version>3.0.0</version> <description>康复中心管理系统</description> <!-- Spring Boot 父项目配置 --> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>3.4.5</version> <!-- Spring Boot 父项目版本 --> <relativePath/> <!--无需导入本地 pom 文件--> </parent> <!-- 项目属性配置 --> <properties> <java.version>17</java.version> <maven.compiler.source>17</maven.compiler.source> <maven.compiler.target>17</maven.compiler.target> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> </properties> <!-- 项目依赖配置 --> <dependencies> <!-- <!– MyBatis 模块 –>--> <!-- <dependency>--> <!-- <groupId>org.mybatis.spring.boot</groupId>--> <!-- <artifactId>mybatis-spring-boot-starter</artifactId>--> <!-- <version>3.0.1</version> <!– MyBatis Spring Boot Starter 版本 –>--> <!-- </dependency>--> <!-- Web 开发模块 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- 安全模块 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <!-- AOP 编程模块 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency> <!-- Redis 消息队列模块 --> <dependency> <groupId>org.springframework.integration</groupId> <artifactId>spring-integration-redis</artifactId> </dependency> <!-- 邮件发送模块 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-mail</artifactId> </dependency> <!-- 数据持久化模块 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <!-- 数据库连接模块 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <!-- 数据库连接池模块 --> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-validator</artifactId> <version>8.0.0.Final</version> </dependency> <!-- Lombok 开发工具,简化 Java Bean 编写 --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> <!-- Spring Boot 热部署模块 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <optional>true</optional> </dependency> <!-- 数据库连接池依赖 --> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>1.2.18</version> </dependency> <!-- MyBatis Plus 持久层框架模块 --> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-spring-boot3-starter</artifactId> <version>3.5.5</version> </dependency> <!-- Redis扩展依赖 --> <dependency> <groupId>org.apache.httpcomponents.client5</groupId> <artifactId>httpclient5</artifactId> <version>5.3.1</version> </dependency> <!-- XML转换依赖 --> <dependency> <groupId>com.thoughtworks.xstream</groupId> <artifactId>xstream</artifactId> <version>1.4.20</version> </dependency> <!-- JSON依赖 --> <dependency> <groupId>com.alibaba.fastjson2</groupId> <artifactId>fastjson2</artifactId> <version>2.0.33</version> </dependency> <!-- Mysql 依赖 --> <dependency> <groupId>com.mysql</groupId> <artifactId>mysql-connector-j</artifactId> <version>8.0.33</version> </dependency> <!-- Swagger 依赖:因为SpringBoot3.0不支持,所以只是为了注释而用 --> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger2</artifactId> <version>3.0.0</version> </dependency> <!-- Hutool 依赖 --> <dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>5.8.19</version> </dependency> <!-- Excel 依赖:请勿更新 --> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooxml</artifactId> <version>3.10-FINAL</version> </dependency> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-scratchpad</artifactId> <version>3.10-FINAL</version> </dependency> <!-- 代码生成依赖:请勿更新 --> <dependency> <groupId>com.ibeetl</groupId> <artifactId>beetl</artifactId> <version>2.9.10</version> </dependency> </dependencies> <!-- 构建配置 --> <build> <plugins> <!-- Spring Boot Maven 插件 --> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <version>3.4.5</version> <!-- Spring Boot Maven Plugin 版本 --> <configuration> <jvmArguments> -Dfile.encoding=UTF-8 -Ddruid.mysql.usePingMethod=false </jvmArguments> </configuration> </plugin> <!-- Maven 编译插件 --> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.11.0</version> <!-- Maven Compiler Plugin 版本 --> <configuration> <source>17</source> <target>17</target> </configuration> </plugin> </plugins> </build> </project>
05-18
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值