什么是Optional
在Java中,Optional是一个用于解决空指针异常的类。它是一个容器对象,可以包含或者不包含非空值。Optional类的设计思想是将可能为空的值封装在一个对象中,并提供一系列的方法来对这个值进行操作,同时避免了空指针异常的发生。
使用Optional可以代替使用null来表示一个值不存在的情况,这样可以提供更加清晰和安全的代码。Optional类提供了许多方法来处理包含或者不包含值的情况,例如:
of(T value)
:创建一个包含指定值的Optional对象,如果指定值为null,则抛出NullPointerException异常。ofNullable(T value)
:创建一个包含指定值的Optional对象,如果指定值为null,则创建一个空的Optional对象。isEmpty()
:判断Optional对象中是否不包含值。isPresent()
:判断Optional对象中是否包含值。get()
:获取Optional对象中的值,如果Optional为空,则抛出NoSuchElementException异常。orElse(T other)
:获取Optional对象中的值,如果Optional为空,则返回指定的默认值。orElseGet(Supplier<? extends T> other)
:获取Optional对象中的值,如果Optional为空,则调用指定的Supplier函数生成默认值。orElseThrow(Supplier<? extends X> exceptionSupplier)
:获取Optional对象中的值,如果Optional为空,则抛出指定的异常。
通过使用Optional类,我们可以更加规范地处理可能为空的值,避免了空指针异常,并使代码更加健壮和可读性更高。
Optional的来源
- Java 中的 Optional 类是在 Java 8 中引入的。它的目的是用于解决空指针异常(NullPointerException)的问题。在旧版本的 Java 中,如果一个方法可能返回空值,那么只能使用 null 来表示,这就导致了很多空指针异常的问题。
- Optional 类的设计思想是将可能为空的值封装在一个对象中,并提供一系列的方法来对这个值进行操作,同时避免了空指针异常的发生。使用 Optional 类可以使代码更加健壮和可读性更高。
- 通过使用 Optional 类,我们可以更加规范地处理可能为空的值,避免了空指针异常,并使代码更加健壮和可读性更高。
Optional方法详解
我们有一个测试对象类
class Dou{ private Integer id; private String name; }
创建Optional
Optional.of(T t)
: 创建一个 Optional 实例,t 必须非空(与map、flatMap配合使用)
Optional<Dou> op = Optional.of(new Dou());
Optional.empty()
: 创建一个空的 Optional 实例
Optional<Dou> op = Optional.empty();
Optional.ofNullable(T t)
:t 可以为null(最常使用)
Optional<Dou> op = Optional.ofNullable(null);
判断Optional容器中是否包含对象
boolean isPresent()
: 判断是否包含对象
Dou dou = null;
Optional<Dou> op = Optional.ofNullable(dou);
System.out.println(op.isPresent());//false
//-----------------------------------------
dou = new Dou();
op = Optional.ofNullable(dou);
System.out.println(op.isPresent());//true
void ifPresent(Consumer<? super T> consumer)
:如果有值,就执行Consumer接口的实现代码,并且该值会作为参数传给它。
Dou dou = new Dou();
Optional<Dou> op = Optional.ofNullable(dou);
System.out.println(dou); //Dou(id=null, name=null)
//只有在不为null的时候执行传入的函数
op.ifPresent(d -> d.setName("an di"));
System.out.println(dou); //Dou(id=null, name=an di)
获取Optional容器的对象:
T get()
: 如果调用对象包含值,返回该值,否则抛异常
Dou dou = null;
Optional<Dou> op = Optional.ofNullable(dou);
System.out.println(op.get());// Exception: "No value present"
Dou dou = new Dou(1,"doudou");
Optional<Dou> op = Optional.ofNullable(dou);
System.out.println(op.get());// TestMain.Dou(id=1, name=doudou)
T orElse(T other)
:如果有值则将其返回,否则返回指定的other对象。
Dou dou = null;
Optional<Dou> op = Optional.ofNullable(dou);
System.out.println(op.orElse(new Dou(1,"doudou")));// TestMain.Dou(id=1, name=doudou)
T orElseGet(Supplier<? extends T> other)
:如果有值则将其返回,否则返回由Supplier接口实现提供的对象。
Dou dou = null;
Optional<Dou> op = Optional.ofNullable(dou);
System.out.println(op.orElseGet(()-> new Dou(1,"doudou")));// TestMain.Dou(id=1, name=doudou)
Dou dou = new Dou(2,"an di");
Optional<Dou> op = Optional.ofNullable(dou);
System.out.println(op.orElseGet(()-> new Dou(1,"doudou")));// TestMain.Dou(id=2, name=an di)
T orElseThrow(Supplier<? extends X> exceptionSupplier)
:如果有值则将其返回,否则抛出由Supplier接口实现提供的异常。
Dou dou = null;
Optional<Dou> op = Optional.ofNullable(dou);
System.out.println(op.orElseThrow(()-> new NullPointerException("为空了哦")));// Exception: 为空了哦
Dou dou = new Dou(1,"doudou");
Optional<Dou> op = Optional.ofNullable(dou);
System.out.println(op.orElseThrow(()-> new NullPointerException("为空了哦")));// TestMain.Dou(id=1, name=doudou)
过滤
Optional<T> filter(Predicate<? super <T> predicate)
:如果值存在,并且这个值匹配给定的
predicate,返回一个Optional用以描述这个值,否则返回一个空的Optional。
Dou dou = new Dou(1,"doudou");
Optional<Dou> op = Optional.ofNullable(dou);
op.filter( o -> o.id.equals(1)).ifPresent(System.out::println);// TestMain.Dou(id=1, name=doudou)
映射
<U>Optional<U> map(Function<? super T,? extends U> mapper)
:如果有值,则对其执行调用映射函数得到返回值。如果返回值不为 null,则创建包含映射返回值的Optional作为map方法返回值,否则返回空Optional。
Dou dou = new Dou(1,"doudou");
Optional<Dou> op = Optional.ofNullable(dou);
op.map( o -> o.name).ifPresent(System.out::println);//doudou
<U> Optional<U> flatMap(Function<? super T, Optional<U>>mapper)
:如果值存在,就对该值执行提供的mapping函数调用,返回一个Optional类型的值,否则就返回一个空的Optional对象
flatMap跟map是一样的只不过他返回的是optional对象。
Dou dou = new Dou(1,"doudou");
Optional<Dou> op = Optional.ofNullable(dou);
op.flatMap( o -> Optional.of(o.getId())).ifPresent(System.out::println);//1
实战
1. ifPresent( )函数使用
- 原先代码
@GetMapping("/get-dateRange/{id}")
public Result getAppointDateRange(@PathVariable("id")Long id) {
PvAppoint appoint = pvAppointService.selectPvAppointById(id);
if (ObjUtil.isEmpty(appoint)){
return success(ListUtil.list(false));
}
DateTime now = DateTime.now();//当前时间
Date beginDate = appoint.getBeginDate();
Date endDate = appoint.getEndDate();
//过滤不在提前预约时间范围内
DateTime isForwardDate = DateTime.of(beginDate).offsetNew(DateField.DAY_OF_MONTH, appoint.minusForwardDate());//提前预约时间=>考试开始时间加上提前天数
if (now.isIn(isForwardDate, endDate)) {//在提前预约时间后 and 在考试结束时间前
//整合时间范围
for (DateTime time : DateUtil.rangeToList(beginDate, endDate, DateField.DAY_OF_YEAR)) {
if (pvHolidayService.isNotHoliday(time)) {//排除节假日
appoint.getDateRange().add(time.toDateStr());
}
}
}
return Result.success(appoint));
}
- 使用Optional后的代码
@GetMapping("/get-dateRange/{id}")
public Result getAppointDateRange(@PathVariable("id")Long id) {
//查询后创建Optional对象
Optional<PvAppoint> optional = Optional.ofNullable(pvAppointService.selectPvAppointById(id));
//如果查询数据不为空则执行ifPresent函数里的代码
optional.ifPresent( appoint -> {
DateTime now = DateTime.now();//当前时间
Date beginDate = appoint.getBeginDate();
Date endDate = appoint.getEndDate();
//过滤不在提前预约时间范围内
DateTime isForwardDate = DateTime.of(beginDate).offsetNew(DateField.DAY_OF_MONTH, appoint.minusForwardDate());//提前预约时间=>考试开始时间加上提前天数
if (now.isIn(isForwardDate, endDate)) {//在提前预约时间后 and 在考试结束时间前
//整合时间范围
for (DateTime time : DateUtil.rangeToList(beginDate, endDate, DateField.DAY_OF_YEAR)) {
if (pvHolidayService.isNotHoliday(time)) {//排除节假日
appoint.getDateRange().add(time.toDateStr());
}
}
}
});
return Result.success(optional.orElse(new PvAppoint()));
}