Hi,大家好,我是抢老婆酸奶的小肥仔。
在咱们日常开发中NullPointerException是永久绕不过去的坑,代码写的欠好,天天都会被它摧残的死去活来,今日咱们来介绍下Optional,这个能让咱们缓解NullPointerException惊骇的工具。
在没有Optional之前,咱们为了防止NullPointerException许多时候都是运用if-else-if来进行条件判别,然后根据条件来获取对应数据。例如:获取赵一所在的职位称号。
List<Expert> experts = Arrays.asList(
new Expert("jiashn","男",20,new Position("总司理",1)),
new Expert("张三","女",21,new Position("财务总监",2)),
new Expert("王五","女",26,new Position("管帐",3)),
new Expert("李四","男",24,new Position("开发部司理",2))
);
//获取赵一所在的职位称号
if(CollectionUtils.isNotEmpty(experts)){
for (Expert expert : experts) {
if (Objects.equals("赵一",expert.getName())){
Position position = expert.getPosition();
if (Objects.nonNull(position)){
System.out.println(position.getName());
}
}
}
}
运用optional就会高雅许多,也会尽量的防止NPE。如:
String name = Optional.of(users.stream().filter(user -> Objects.equals("赵一", user.getName())).findFirst())
.get()
.map(SystemUser::getPosition)
.map(Position::getName)
.orElse("");
System.out.println("Optional获取职位称号:" + name);
上述代码比照中,咱们能够明晰感觉到运用Optional代码比较高雅,也没有很多代码判空,即使数据不存在也没报NPE,防止了NPE.
Optional是JDK1.8后引入的一个新特性,通常被认为是用于缓解java中NPE问题。Optional作为容器,能够保存类型T的值,也能够直接保存null。
接下来咱们介绍下Optional的一些办法。
Optional办法
准备工作,创立一个有数据的系统用户,一个为null的数据。
/**
* @author: jiangjs
* @description: 系统用户
* @date: 2023/5/8 11:40
**/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class SystemUser {
private String name;
private String gender;
private Integer age;
private Position position;
public Optional<Position> optionalPosition(){
return Optional.ofNullable(position);
}
}
/**
* @author: jiangjs
* @description: 职位
* @date: 2023/5/8 11:20
**/
@Data
@AllArgsConstructor
public class Position {
/**
* 职位称号
*/
private String name;
/**
* 职位等级
*/
private Integer level;
}
SystemUser systemUser = new SystemUser("王五","女",26,new Position("管帐",3));
SystemUser user = null;
empty
static<T> Optional<T> empty()
:静态办法,回来空的Optional。
源码:
private static final Optional<?> EMPTY = new Optional<>();
public static<T> Optional<T> empty() {
@SuppressWarnings("unchecked")
Optional<T> t = (Optional<T>) EMPTY;
return t;
}
实现:
//empty
Object o = Optional.empty();
System.out.println("empty:" + o);
输出:
empty:Optional.empty
of、ofNullable
static <T> Optional<T> of(T value)
:创立一个非空的Optional,当T为null时,则抛出NPE。
static <T> Optional<T> ofNullable(T value)
:假如T不为空,则创立指定值的Optional,不然回来空的Optional。
//of ofNullable
Optional<SystemUser> systemUserOptional = Optional.of(systemUser);
System.out.println("systemUserOptional:" + systemUserOptional);
Optional<SystemUser> userOptional = Optional.of(user);
System.out.println("userOptional:" + userOptional);
Optional<SystemUser> optionalSystemUser = Optional.ofNullable(systemUser);
System.out.println("optionalSystemUser:" + optionalSystemUser);
Optional<SystemUser> optionalUser = Optional.ofNullable(user);
System.out.println("optionalUser:" + optionalUser);
输出:
systemUserOptional:Optional[SystemUser(name=王五, gender=女, age=26, position=Position(name=管帐, level=3))]
java.lang.NullPointerException
optionalSystemUser:Optional[SystemUser(name=王五, gender=女, age=26, position=Position(name=管帐, level=3))]
optionalUser:Optional.empty
Optional.of(user):报了空指针异常,这是由于of在创立Optional时,会对T进行判空处理。源码:
public static <T> Optional<T> of(T value) {
return new Optional<>(value);
}
private Optional(T value) {
this.value = Objects.requireNonNull(value);
}
Optional.ofNullable(user):运用了三目运算符,假如T为空,则调用empty(),回来空的Optional。
源码:
public static <T> Optional<T> ofNullable(T value) {
return value == null ? empty() : of(value);
}
isPresent()
isPresent()
:判别是否包括指定值,包括回来true,反之回来false。
//isPresent
boolean present = Optional.of(systemUser).isPresent();
System.out.println("systemUser是否存在:" + present);
boolean judge = Optional.ofNullable(user).isPresent();
System.out.println("user是否存在:" + judge);
输出:
systemUser是否存在:true
user是否存在:false
isPresent():直接获取Optional中的T来判空。源码:
public boolean isPresent() {
return value != null;
}
注:在写代码时,不要即用了if,又用isPresent来进行判别,如:if (Optional.ofNullable(user).isPresent()){事务代码},这样消除不了繁琐的if判别,也创立了Optional目标。
orElse、orElseGet
T orElseGet(Supplier<? extends T> other)
:假如调用目标包括值,则回来该值,不然回来other。
T orElse(T other)
:假如调用目标包括值,则回来该值,不然回来other。
//orElseGet,orElse
SystemUser orElseGetUser = Optional.ofNullable(user).orElseGet(UseOptional::getSystemUser);
System.out.println("orElseGetUser:" + orElseGetUser);
SystemUser orElseUser = Optional.ofNullable(user).orElse(getSystemUser());
System.out.println("orElseUser:" + orElseUser);
System.out.println("-------------------------------------------------------------");
SystemUser orElseGetSystemUser = Optional.of(systemUser).orElseGet(UseOptional::getSystemUser);
System.out.println("orElseGetSystemUser:" + orElseGetSystemUser);
SystemUser orElseSystemUser = Optional.of(systemUser).orElse(getSystemUser());
System.out.println("orElseSystemUser:" + orElseSystemUser);
输出:
默认数据:SystemUser(name=李四, gender=男, age=24, position=Position(name=开发部司理, level=2))
orElseGetUser:SystemUser(name=李四, gender=男, age=24, position=Position(name=开发部司理, level=2))
默认数据:SystemUser(name=李四, gender=男, age=24, position=Position(name=开发部司理, level=2))
orElseUser:SystemUser(name=李四, gender=男, age=24, position=Position(name=开发部司理, level=2))
orElseGetSystemUser:SystemUser(name=王五, gender=女, age=26, position=Position(name=管帐, level=3))
默认数据:SystemUser(name=李四, gender=男, age=24, position=Position(name=开发部司理, level=2))
orElseSystemUser:SystemUser(name=王五, gender=女, age=26, position=Position(name=管帐, level=3))
当调用目标不包括值时,尽管两者都是回来other,可是从界说中咱们能够看到orElseGet是运用了Supplier函数式编程,而orElse直接运用T。上面例子也说明晰orElse会提早创立T而orElseGet会在判别调用目标没有时才会调用Supplier来创立other。
orElse与orElseGet差异:
orElse:不管调用目标是否存在,都会提早创立T。
orElseGet:只有当调用目标不存在时,才会运用Supplier创立回来值。
get
get():即获取Optional的目标数据,假如目标数据不存在则抛出异常:NoSuchElementException
//get
SystemUser getSystemUser = Optional.ofNullable(systemUser).get();
System.out.println("getSystemUser:" + getSystemUser);
SystemUser getUser = Optional.ofNullable(user).get();
System.out.println("getUser:" + getUser);
输出:
getSystemUser:SystemUser(name=王五, gender=女, age=26, position=Position(name=管帐, >level=3))
Exception in thread “main” java.util.NoSuchElementException: No value present
at java.util.Optional.get(Optional.java:135)
at com.jiashn.springbootproject.useUtil.UseOptional.main(UseOptional.java:86)
map、flatMap
<U> Optional<U> map(Function<? super T, ? extends U> mapper)
:假如有值,则进行数据处理,假如没有值,则回来Optional.empty()。
<U> Optional<U> flatMap(Function<? super T, Optional<U>> mapper)
:与map相似,要求回来值必须是Optional。
//map
String sysUserName = Optional.of(systemUser).map(SystemUser::getName).get();
System.out.println("sysUserName:" + sysUserName);
Optional<String> userName = Optional.ofNullable(user).map(SystemUser::getName);
System.out.println("userName:" + userName);
//flatMap
String name = Optional.of(systemUser)
.flatMap(SystemUser::optionalPosition)
.map(Position::getName).get();
System.out.println("name:" + name);
输出:
sysUserName:王五
userName:Optional.empty
name:管帐
上述便是Optional提供一些办法,咱们在实际开发中应灵活运用,通常Optional会跟Stream进行联合运用。例如:获取上述调集性别为女的,然后获取过滤后调集的第一个元素,数据不存在时创立新的目标。
Expert expert = Optional.of(experts.stream().filter(ex -> Objects.equals("女",ex.getGender())).findFirst())
.get()
.orElseGet(Expert::new);
这样子在后面运用expert就能防止出现NPE.
jdk引入了Optional能让咱们快捷的获取比较复杂的数据结构中的数据,同时也能有用防止NPE,当然Optional办法单独运用可能作用不大,可是组合运用时会让咱们事半功倍。