Optional
前言
我的使用
package yimeng;
import com.ruoyi.RuoYiApplication;
import com.ruoyi.common.core.domain.entity.SysUser;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.*;
@SpringBootTest(classes = RuoYiApplication.class)
public class MyTest2 {
@Test
public void testOptional() {
List<SysUser> list=new ArrayList<>();
SysUser sysUser1=new SysUser(1L,"张三");
SysUser sysUser2=new SysUser(1L,"李四");
SysUser sysUser3=new SysUser(3L,"王五");
list.add(sysUser1);
list.add(sysUser2);
list.add(sysUser3);
Optional<SysUser> optionalSysUser = list.stream().filter((item) -> item.getUserId().compareTo(1L) == 0L).findFirst();
SysUser sysUser = optionalSysUser.get();
System.out.println(sysUser);//打印了“张三”这个用户
}
}
雨泽的使用
package yimeng;
import com.ruoyi.RuoYiApplication;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.system.mapper.SysUserMapper;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;
@SpringBootTest(classes = RuoYiApplication.class)
public class MyTest2 {
@Resource
private SysUserMapper sysUserMapper;
@Test
public void testOptional2() {
SysUser sysUser = sysUserMapper.selectUserById(1L);
String s = Optional.ofNullable(sysUser)
.map(SysUser::getUserName)
.orElseThrow(() -> new RuntimeException("id是1L的用户为null"));
System.out.println(s);
SysUser sysUser1 = sysUserMapper.selectUserById(100L);
Optional.ofNullable(sysUser1)
.map(SysUser::getUserName)
.orElseThrow(() -> new RuntimeException("id是100L的用户为null或者名字为null"));
}
}
结果:
这里不知道他有没有走map方法。
但是通过看源码可以知道。其实他是走了map方法的,但是为什么没有抛出空指针异常呢?你null.map()了。
因为他内部把null转换了一下,你Optional.ofNullable(sysUser)返回值不是null了。所以调用map方法不会出现空指针异常。如果sysUser是空,相当于是返回一个private static final Optional<?> EMPTY = new Optional<>();
的东西。
然后用这个东西去调用map方法,map方法也是先看你是不是空对应的Optional,看到是调用者是空对应的Optional,也返回一个private static final Optional<?> EMPTY = new Optional<>();
,不会去执行真正map()方法中的lambda表达式的,所以看起来像是跳过了map中的逻辑直接执行了orElseThrow方法。
探测:
探测:
ofNullable()参数为null不抛出空指针异常的原因:
filter()参数为null抛出空指针异常的原因:
API详细介绍
Optional 就相当于是一个对象容器。
初始化方法
of(T t)
功能:创建Optional实例
注意:创建对象时传入的参数不能为null。如果传入参数为null,则抛出NullPointerException 。
@Test
public void test(){
// 创建Optional实例:参数非null
Optional<String> notNullOptional = Optional.of("xiaoxian");
System.out.println(notNullOptional);
// 创建Optional实例:参数为null,抛出 NullPointerException
try {
Optional<String> nullOptional = Optional.of(null);
} catch (NullPointerException e) {
System.out.println("【of()】" + e.getMessage());
// 输出:java.lang.NullPointerException
e.printStackTrace();
}
}
探测:
探测:
探测:
ofNullable(T t)
功能:创建Optional实例
注意:如果指定的值为null,则返回一个空的Optional。
@Test
public void test(){
// ofNullable()与of()相似,区别在于:ofNullable()是可以接受参数为null的情况。
// 创建Optional实例:参数非null
Optional<String> notNullOptional = Optional.ofNullable("xiaoxian");
// 创建Optional实例:参数为null,不会报错,返回一个空的Optional实例
Optional<String> nullOptional = Optional.ofNullable(null);
}
empty()
功能:创建空的Optional实例
@Test
public void test(){
Optional<String> emptyOptional = Optional.empty();
System.out.println(emptyOptional);
}
获取
get()
@Test
public void test(){
Optional<String> notNullOptional = Optional.ofNullable("xiaoxian");
System.out.println(notNullOptional.get());
Optional<String> emptyOptional = Optional.empty();
System.out.println(emptyOptional.get());
}
get():获取optional容器中的对象,当optional 容器为空时报错。返回值为容器中那个对象的类型。
探测:
因为get方法,返回的是Optional对象声明时的那个泛型,不是返回一个Optional对象,所以get()后无法使用Optional的orElseThrow方法。
判断
isPresent()
isPresent():判断optional是否为空,如果空则返回false,否则返回true
@Test
public void test(){
// 创建Optional实例:参数非null
Optional<String> notNullOptional = Optional.ofNullable("xiaoxian");
// 创建Optional实例:参数为null,不会报错,返回一个空的Optional实例
Optional<String> nullOptional = Optional.ofNullable(null);
// 输出:true
System.out.println("【isPresent()】" + notNullOptional.isPresent());
// 输出:false
System.out.println("【isPresent()】" + nullOptional.isPresent());
}
ifPresent(Consumer consumer)
ifPresent(Consumer c):如果optional不为空,则将optional中的对象传给Comsumer函数,去执行对应的方法。如果为空,不执行什么操作。ifPresent方法的返回是void,所以也不会返回什么东西。
@Test
public void test(){
// 创建Optional实例:参数非null
Optional<String> notNullOptional = Optional.ofNullable("xiaoxian");
//如果实例值非null,就执行lambda表达式,否则不处理
notNullOptional.ifPresent(s -> {
s = s + " love java";
// 输出:xiaoxian love java
System.out.println(s);
});
}
Else相关
orElse()和orElseGet()
我们在初始化 Optional 对象的时候,有时候需要一个默认值,这时orElse() 和 orElseGet() 方法就派上用场了(类似三目运算符)。
orElse()功能:检查Optional容器中的对象是否是null,如果非null,就返回这个对象。否则返回你自己指定的其它值。
@Test
public void test(){
String name = Optional.ofNullable("张三").orElse("沉默王二");
System.out.println(name); // 输出:张三
String nullName = null;
String name1 = Optional.ofNullable(nullName).orElse("沉默王二");
System.out.println(name1); // 输出:沉默王二
}
注意:是返回orElse方法不管,调用它的Optional是不是为空的容器,都会返回它声明的泛型的对象。不是要以为Optional.ofNullable(“张三”).orElse(“沉默王二”);返回还是Optional对象哈。看清楚上面的例子返回的是一个String,不是一个Optional对象哈。
orElseGet()功能:orElseGet() 方法与 orElse() 方法类似,但参数类型不同。orElseGet()方法的功能是,如果 Optional 容器中的对象为 null,则执行参数中的lambda表达式的方法。
@Test
public void test(){
Optional<String> notNullOptional = Optional.ofNullable("xiaoxian");
Optional<String> nullOptional = Optional.ofNullable(null);
// orElseGet与orElse方法类似
// 区别在于:orElse传入的是默认值,orElseGet可以接收一个lambda表达式生成默认值
//如果Optional实例值非null,返回Optional的值
// 输出:xiaoxian
System.out.println("【orElseGet()】" + notNullOptional.orElseGet(() -> "Default Value"));
//如果Optional实例值为null,返回lambda表达式的值
// 输出:Default Value
System.out.println("【orElseGet()】" + nullOptional.orElseGet(() -> "Default Value"));
}
从输出结果以及代码的形式上来看,这两个方法极其相似,这不免引起我们的怀疑,Java 类库的设计者有必要这样做吗?
假设现在有这样一个获取默认值的方法,很传统的方式
public static String getDefaultValue() { System.out.println("getDefaultValue"); return "沉默王二"; }
然后,通过 orElse() 方法和 orElseGet() 方法分别调用 getDefaultValue() 方法返回默认值
public static void main(String[] args) { String name = null; System.out.println("orElse"); String name2 = Optional.ofNullable(name).orElse(getDefaultValue()); System.out.println("orElseGet"); String name3 = Optional.ofNullable(name).orElseGet(Demo::getDefaultValue); }
注:类名 :: 方法名是 Java 8 引入的语法,方法名后面是没有 () 的,表明该方法并不一定会被调用
输出结果如下所示:
orElse getDefaultValue orElseGet getDefaultValue
输出结果是相似的,没什么太大的不同,这是在 Optional 对象的值为 null 的情况下。假如 Optional 对象的值不为 null 呢?
public static void main(String[] args) { String name = "沉默王三"; System.out.println("orElse"); String name2 = Optional.ofNullable(name).orElse(getDefaultValue()); System.out.println("orElseGet"); String name3 = Optional.ofNullable(name).orElseGet(OrElseOptionalDemo::getDefaultValue); }
输出结果如下所示:
orElse getDefaultValue orElseGet
在Optional容器中的对象不是null时,orElseGet() 并没有去调用 getDefaultValue()方法,而orElse方法还是会去调用的,只是返回值没有被使用而已。所以orElseGet方法的性能更佳。
直观从语义上来看,get() 方法才是最正宗的获取 Optional 对象值的方法,但很遗憾,该方法是有缺陷的,因为假如 Optional 容器中的值为 null,该方法会抛出 NoSuchElementException 异常。这完全与我们使用 Optional 类的初衷相悖。我们使用 Optional 其实就是为了防止异常。主要是防止空指针异常。如果是空的话,会把null转换为对应的Optional,所以不会出现空指针异常,你使用Optional的get方法,如果Option容器中的对象为null,就会抛出NoSuchElementException 异常,虽然这个不是空指针异常,但是也是异常,所以不建议使用Optional的get方法。
orElseThrow()
功能:检查Optional容器中的实例是否为null,如果容器中实例值非null,就不做任何处理,如果是null,则抛异常Exception
@Test
public void test(){
Optional<String> notNullOptional = Optional.ofNullable("xiaoxian");
Optional<String> nullOptional = Optional.ofNullable(null);
// orElseThrow与orElse方法类似
// 区别在于:orElse传入的是默认值,orElseThrow会抛出他参数中的lambda表达式或方法生成的异常
try {
//如果Optional实例值非null,不做任何处理,不会执行orElseThrow()内的方法。
notNullOptional.orElseThrow(Exception::new);
} catch (Exception e) {
e.printStackTrace();
}
try {
//如果Optional实例值为null,会执行orElseThrow()内对象的方法。并且这个orElseThrow内对象的方法必须是可以抛的,即异常对象。
nullOptional.orElseThrow(Exception::new);
} catch (Throwable e) {
// 输出: null
System.out.println("【orElseThrow()】" + e.getMessage());
e.printStackTrace();
}
}
探测:
看到orElseThrow方法中的对象的get方法的返回值必须是一个可被抛出的对象,所以orElseThrow方法中对象的方法都是创建一个异常类。(Supplier他就一个方法,如果是lambda表达式,那么lambda表达式中的方法体就是这个get方法的方法体,这是lambda表达式的知识点。)
过滤
filter(Predicate p)
filter(Predicate p):如果optional容器中的对象不为空,则执行断言函数p,如果p的结果为true,则返回原本的optional,否则返回空的optional。如果optional容器中的对象为空,那么也返回空的Optional。
@Test
public void test(){
Optional<String> notNullOptional = Optional.ofNullable("xiaoxian");
//如果是空,就返回空Optional
Optional<String> nullOptional = Optional.ofNullable(null);
Optional<String> aaa = nullOptional.filter(item -> item.equals("kkk"));
System.out.println(aaa);
// 如果不是空,且满足filter条件,则返回该Option容器中的对象实例,否则返回空Optional。value就是指Optional容器中的对象。
Optional<String> filterTrue = notNullOptional.filter((value) -> value.length() > 6);
//输出:xiaoxian
System.out.println("【filter】" + filterTrue.orElse("不滿足filter條件"));
//如果不是空,且不满足filter条件,则返回空Optional。value就是指Optional容器中的对象。
Optional<String> filterFalse = notNullOptional.filter((value) -> value.length() > 10);
//输出:【filter】Optional.empty
System.out.println("【filter】" + filterFalse);
}
映射
map(Function<T, U> mapper)
map(Function<T, U> mapper):如果optional容器中对象不为空,则将optional中的对象 t 映射成另外一个对象 u,并将 u 存放到一个新的optional容器中。否则返回空Optional。
@Test
public void test(){
Optional<String> notNullOptional = Optional.ofNullable("xiaoxian");
//如果是空,就返回空Optional
Optional<String> nullOptional = Optional.ofNullable(null);
// 如果Optional实例值非null,执行map(lambda表达式,任意类型),返回新的Optional实例
Optional<String> notNullToUpperCase = notNullOptional.map((value) -> value.toUpperCase());
// 输出:map后是一个新的Optional对象
System.out.println(notNullOptional==notNullToUpperCase?"是一个对象":"map后是一个新的Optional对象");
// 输出:XIAOXIAN
System.out.println("【map()】" + notNullToUpperCase.orElse("No value found"));
Optional<Integer> notNullToInteger = notNullOptional.map((value) -> 1);
// 输出:1
System.out.println("【map()】" + notNullToInteger.orElse(2));
// 如果Optional实例值为null,不用执行map(),返回空Optional
Optional<String> emptyToUpperCase = nullOptional.map((value) -> value.toUpperCase());
// 输出:No value found
System.out.println("【map()】" + emptyToUpperCase.orElse("No value found"));
}
flatMap(Function< T,Optional< U >> mapper)
flatMap():flatMap()与 map()类似,区别在于:他们传入方法的lambda表达式的返回类型
map():lambda表达式返回值可以是任意类型,在map函数返回之前会包装为Optional
flatMap:lambda表达式返回值必须是Optionl实例,不会自动把结果包装为Optional,需要你手动把返回值封装为Optional才行。
@Test
public void test(){
Optional<String> notNullOptional = Optional.ofNullable("xiaoxian");
//如果是空,就返回空Optional
Optional<String> nullOptional = Optional.ofNullable(null);
// flatMap()与 map()类似,区别在于:传入方法的lambda表达式的返回类型
// map():lambda表达式返回值可以是任意类型,在map函数返回之前会包装为Optional
// flatMap:lambda表达式返回值必须是Optionl实例,不会把结果包装为Optional
//如果Optional容器中对象的值非null,执行flatMap(lambda表达式),但是注意得返回一个Optional类型的返回值
Optional<String> notNullToUpperCase = notNullOptional.flatMap((value) -> Optional.of(value.toUpperCase()));
// 输出:XIAOXIAN
System.out.println("【flatMap()】" + notNullToUpperCase.orElse("No value found"));
//如果Optional容器中实例的值为null,不用执行flatMap(lambda表达式),返回空Optional
Optional<String> optional = nullOptional.flatMap((value) -> Optional.of(value.toUpperCase()));
// 输出:No value found
System.out.println("【flatMap()】" + optional.orElse("No value found"));
}
使用推荐
1、如果实例值不为null,就返回值,否则为null
// 之前写法
User user1 = userOptional.isPresent() ? userOptional.get() : null;
// 推荐写法
User user2 = userOptional.orElse(null);
2、如果实例值不为null,就返回值,否则进行指定操作
// 之前写法
User user3 = userOptional.isPresent() ? userOptional.get(): getUser();
// 推荐写法
User user4 = userOptional.orElseGet(() -> getUser());
3、如果实例值不为null,就进行指定操作
// 之前写法
if (userOptional.isPresent()) {
System.out.println(userOptional.get());
}
// 推荐写法
userOptional.ifPresent(System.out::println);
// 之前写法
if (userOptional.isPresent()) {
getUser();
}
// 推荐写法
userOptional.ifPresent(e->getUser());
4、如果实例值不为null,就获取实例值,并进行指定操作
// 之前写法
List<String> list = null;
if(userOptional.isPresent()) {
list = userOptional.get().getCourseList();
} else {
list = Collections.emptyList();
}
// 推荐写法
list = userOptional.map(u -> u.getCourseList()).orElse(Collections.emptyList());
// 之前写法
getName(new User("xiaoxian"));
// 推荐写法
getNameNew(new User("xiaoxian"));
public static String getName(User user){
if(user != null) {
String name = user.getName();
if(name != null) {
return name.toUpperCase();
} else {
return null;
}
} else {
return null;
}
}
public static String getNameNew(User user){
Optional<User> userOptional = Optional.ofNullable(user);
return userOptional.map(u -> u.getName())
.map(name -> name.toUpperCase())
.orElse(null);
}
推荐示例代码
import java.util.Collections;
import java.util.List;
public class UseOptional {
public static User getUser() {
return new User("xiaoxian");
}
public static void main(String[] args) {
Optional<User> userOptional = Optional.of(new User("xiaoxian"));
// 之前写法
User user1 = userOptional.isPresent() ? userOptional.get() : null;
// 推荐写法
User user2 = userOptional.orElse(null);
// 之前写法
User user3 = userOptional.isPresent() ? userOptional.get() : getUser();
// 推荐写法
User user4 = userOptional.orElseGet(() -> getUser());
// 之前写法
if (userOptional.isPresent()) {
System.out.println(userOptional.get());
}
// 推荐写法
userOptional.ifPresent(System.out::println);
// 之前写法
if (userOptional.isPresent()) {
getUser();
}
// 推荐写法
userOptional.ifPresent(e -> getUser());
// 之前写法
List<String> list = null;
if (userOptional.isPresent()) {
list = userOptional.get().getCourseList();
} else {
list = Collections.emptyList();
}
// 推荐写法
list = userOptional.map(u -> u.getCourseList()).orElse(Collections.emptyList());
// 之前写法
getName(new User("xiaoxian"));
// 推荐写法
getNameNew(new User("xiaoxian"));
}
public static String getName(User user) {
if (user != null) {
String name = user.getName();
if (name != null) {
return name.toUpperCase();
} else {
return null;
}
} else {
return null;
}
}
public static String getNameNew(User user) {
Optional<User> userOptional = Optional.ofNullable(user);
return userOptional.map(u -> u.getName()).map(name -> name.toUpperCase()).orElse(null);
}
}
class User {
public String name;
public List<String> courseList;
public User() {
}
public User(String name) {
this.name = name;
}
public String getName() {
return name;
}
public List<String> getCourseList() {
return courseList;
}
}